GUI component interaction: Difference between revisions
m omit batch files, BF, PostsScript |
+Java |
||
Line 347: | Line 347: | ||
<lang j>interact_run''</lang> |
<lang j>interact_run''</lang> |
||
=={{header|Java}}== |
|||
{{works with|Swing}} |
|||
{{works with|AWT}} |
|||
There are nice GUI editors in some IDEs (Netbeans has a notoriously good one), but this GUI was not built automatically, so it's a little easier to understand. |
|||
<lang java>import java.awt.GridLayout; |
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
import java.awt.event.KeyEvent; |
|||
import java.awt.event.KeyListener; |
|||
import javax.swing.JButton; |
|||
import javax.swing.JFrame; |
|||
import javax.swing.JOptionPane; |
|||
import javax.swing.JPanel; |
|||
import javax.swing.JTextField; |
|||
public class Interact extends JFrame{ |
|||
final JTextField numberField; |
|||
final JButton incButton, randButton; |
|||
public Interact(){ |
|||
//stop the GUI threads when the user hits the X button |
|||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
|||
numberField = new JTextField(); |
|||
incButton = new JButton("Increment"); |
|||
randButton = new JButton("Random"); |
|||
numberField.setText("0");//start at 0 |
|||
//listen for button presses in the text field |
|||
numberField.addKeyListener(new KeyListener(){ |
|||
@Override |
|||
public void keyTyped(KeyEvent e) { |
|||
//if the entered character is not a digit |
|||
if(!Character.isDigit(e.getKeyChar())){ |
|||
//eat the event (i.e. stop it from being processed) |
|||
e.consume(); |
|||
} |
|||
} |
|||
@Override |
|||
public void keyReleased(KeyEvent e){} |
|||
@Override |
|||
public void keyPressed(KeyEvent e){} |
|||
}); |
|||
//listen for button clicks on the increment button |
|||
incButton.addActionListener(new ActionListener(){ |
|||
@Override |
|||
public void actionPerformed(ActionEvent e) { |
|||
String text = numberField.getText(); |
|||
if(text.isEmpty()){ |
|||
numberField.setText("1"); |
|||
}else{ |
|||
numberField.setText((Long.valueOf(text) + 1) + ""); |
|||
} |
|||
} |
|||
}); |
|||
//listen for button clicks on the random button |
|||
randButton.addActionListener(new ActionListener(){ |
|||
@Override |
|||
public void actionPerformed(ActionEvent e) { |
|||
//show a dialog and if they answer "Yes" |
|||
if(JOptionPane.showConfirmDialog(null, "Are you sure?") == |
|||
JOptionPane.YES_OPTION){ |
|||
//set the text field text to a random positive long |
|||
numberField.setText(Long.toString((long)(Math.random() |
|||
* Long.MAX_VALUE))); |
|||
} |
|||
} |
|||
}); |
|||
//arrange the components in a grid with 2 rows and 1 column |
|||
setLayout(new GridLayout(2, 1)); |
|||
//a secondary panel for arranging both buttons in one grid space in the window |
|||
JPanel buttonPanel = new JPanel(); |
|||
//the buttons are in a grid with 1 row and 2 columns |
|||
buttonPanel.setLayout(new GridLayout(1, 2)); |
|||
//add the buttons |
|||
buttonPanel.add(incButton); |
|||
buttonPanel.add(randButton); |
|||
//put the number field on top of the buttons |
|||
add(numberField); |
|||
add(buttonPanel); |
|||
//size the window appropriately |
|||
pack(); |
|||
} |
|||
public static void main(String[] args){ |
|||
new Interact().setVisible(true); |
|||
} |
|||
}</lang> |
|||
=={{header|Liberty BASIC}}== |
=={{header|Liberty BASIC}}== |
||
===Input Verification=== |
===Input Verification=== |
Revision as of 17:50, 28 April 2011
You are encouraged to solve this task according to the task description, using any language you may know.
Almost every application needs to communicate with the user in some way. Therefore, a substantial part of the code deals with the interaction of program logic with GUI components. Typically, the following is needed:
- put values into input fields under program control
- read and check input from the user
- pop up dialogs to query the user for further information
The task: For a minimal "application", write a program that presents a form with three components to the user: A numeric input field ("Value") and two buttons ("increment" and "random").
The field is initialized to zero. The user may manually enter a new value into the field, or increment its value with the "increment" button. Entering a non-numeric value should be either impossible, or issue an error message.
Pressing the "random" button presents a confirmation dialog, and resets the field's value to a random value if the answer is "Yes".
(This task may be regarded as an extension of the task Simple windowed application).
AutoHotkey
<lang AutoHotkey>GUI, add, Edit,Number w50 vUserInput, 0 ; Number Specifies Numbers-only, but other characters can still be pasted in, ; Making our own check necessary. (MakeSure)
GUI, add, Button, gIncrement, Increment ; Instead of an increment button, the UpDown control could be used, but this was not specified. GUI, add, Button, gRando, Random Gui, Show, W200 y200, Title ; Shows the GUI with a width and height of 200px SetTimer, MakeSure, 1000 ; Runs MakeSure every second return ; End Auto-Execute Section
Increment:
Gui, Submit, NoHide
- The above line assigns all variables associated with controls to the state of that control, but leaves the GUI visible.
If UserInput is not Number { MsgBox, %userInput% is not a number. GUIControl,,UserInput, 0 ; Reset the Edit control to 0 } Else { UserInput++ GUIControl,, UserInput, %UserInput% ; Sets the value of the Edit control } return
Rando: MsgBox, 4, Title, Are you sure you want to randomize? ; Specify your own title. 4 means YesNo IfMsgBox, Yes { Random, UserInput, 1, 999 ; random number from 1-999 GUIControl,, UserInput, %UserInput% ; Sets the value of the Edit control } return
MakeSure: Gui, Submit, NoHide If UserInput is not Number { If (UserInput<>"") { Msgbox Error! Numbers Only! GUIControl,, UserInput, 0 } } return
GUIClose: ExitApp ; Makes sure the script exits when the window is closed, ; Otherwise the script is persistent because it contains ; a timer.</lang>
C++
with library Qt 4.4 , using (under Linux) first qmake -project and then qmake -o Makefile <projectfile>, then make
file interaction.h
<lang c++>#ifndef INTERACTION_H
- define INTERACTION_H
- include <QWidget>
class QPushButton ; class QLineEdit ; class QVBoxLayout ; class MyWidget : public QWidget {
Q_OBJECT
public :
MyWidget( QWidget *parent = 0 ) ;
private :
QLineEdit *entryField ; QPushButton *increaseButton ; QPushButton *randomButton ; QVBoxLayout *myLayout ;
private slots :
void doIncrement( ) ; void findRandomNumber( ) ;
} ;
- endif</lang>
file interaction.cpp
<lang c++>#include <QPushButton>
- include <QLineEdit>
- include <QMessageBox>
- include <QString>
- include <QRegExpValidator>
- include <QVBoxLayout>
- include <QRegExp>
- include <ctime> //for the srand initialization
- include <cstdlib> //for the random number
- include "interaction.h"
MyWidget::MyWidget (QWidget *parent ) : QWidget( parent ) {
myLayout = new QVBoxLayout( ) ; entryField = new QLineEdit( "0" ) ; QRegExp rx( "\\d+" ) ; QValidator *myvalidator = new QRegExpValidator( rx , this ) ; entryField->setValidator( myvalidator ) ; increaseButton = new QPushButton( "increase" ) ; connect( increaseButton, SIGNAL( clicked( ) ) ,
this , SLOT( doIncrement( ) )) ;
randomButton = new QPushButton( "random" ) ; connect( randomButton , SIGNAL( clicked( ) ) ,
this , SLOT ( findRandomNumber( ) )) ;
myLayout->addWidget( entryField ) ; myLayout->addWidget( increaseButton ) ; myLayout->addWidget( randomButton ) ; setLayout( myLayout ) ;
}
void MyWidget::doIncrement( ) {
bool ok ; int zahl = entryField->text( ).toInt( &ok, 10 ) ; entryField->setText( QString( "%1").arg( ++zahl ) ) ;
}
void MyWidget::findRandomNumber( ) {
QMessageBox msgBox( this ) ; msgBox.setText( "Do you want to create a random number ?" ) ; msgBox.setStandardButtons( QMessageBox::Yes | QMessageBox::No ) ; int ret = msgBox.exec( ) ; switch ( ret ) { case QMessageBox::Yes :
srand( time( 0 ) ) ; int zahl = random( ) ; entryField->setText( QString( "%1" ).arg( zahl )) ; break ;
}
}</lang>
file main.cpp
<lang c++>#include <QApplication>
- include "interaction.h"
int main( int argc , char *argv[ ] ) {
QApplication app( argc, argv ) ; MyWidget theWidget ; theWidget.show( ) ; return app.exec( ) ;
}</lang>
C_sharp
C# 3.0 with Windows Forms; compile as csc -t:winexe Program.cs on MS.NET or as gmcs -t:winexe Program.cs on Mono. <lang c_sharp>using System; using System.ComponentModel; using System.Windows.Forms;
class RosettaInteractionForm : Form {
// Model used for DataBinding. // Notifies bound controls about Value changes. class NumberModel: INotifyPropertyChanged {
Random rnd = new Random();
// initialize event with empty delegate to avoid checks on null public event PropertyChangedEventHandler PropertyChanged = delegate {};
int _value; public int Value { get { return _value; } set { _value = value; // Notify bound control about value change PropertyChanged(this, new PropertyChangedEventArgs("Value")); } }
public void ResetToRandom(){ Value = rnd.Next(5000); } }
NumberModel model = new NumberModel{ Value = 0}; RosettaInteractionForm() { //MaskedTextBox is a TextBox variety with built-in input validation var tbNumber = new MaskedTextBox { Mask="0000", // allow 4 decimal digits only ResetOnSpace = false, // don't enter spaces Dock = DockStyle.Top // place at the top of form }; // bound TextBox.Text to NumberModel.Value; tbNumber.DataBindings.Add("Text", model, "Value");
var btIncrement = new Button{Text = "Increment", Dock = DockStyle.Bottom}; btIncrement.Click += delegate { model.Value++; }; var btDecrement = new Button{Text = "Decrement", Dock = DockStyle.Bottom}; btDecrement.Click += delegate { model.Value--; }; var btRandom = new Button{ Text="Reset to Random", Dock = DockStyle.Bottom }; btRandom.Click += delegate { if (MessageBox.Show("Are you sure?", "Are you sure?", MessageBoxButtons.YesNo) == DialogResult.Yes) model.ResetToRandom(); }; Controls.Add(tbNumber); Controls.Add(btIncrement); Controls.Add(btDecrement); Controls.Add(btRandom); } static void Main() { Application.Run(new RosettaInteractionForm()); }
} </lang>
Fantom
<lang fantom> using fwt using gfx
class GuiComponent {
public static Void main () { Window { title = "Rosetta Code: Gui component" size = Size(350, 200) textField := Text { onModify.add |Event e| { Text thisText := e.widget if (thisText.text != "") // if nonempty string { try (thisText.text.toInt) // try converting to int catch thisText.text = "" // clear field if does not work } } } GridPane { numCols = 1 textField, Button { text = "increment" onAction.add |Event e| { // make sure there is a number to increment, else set field to 0 if (textField.text == "") { textField.text = "0" } else { try { Int x := textField.text.toInt textField.text = (x+1).toStr } catch { textField.text = "0" } } } }, Button { text = "random" onAction.add |Event e| { if (Dialog.openQuestion(e.window, "Make number random?", null, Dialog.yesNo) == Dialog.yes) { textField.text = Int.random(1..10000).toStr } } }, }, }.open }
} </lang>
J
<lang j>INTERACT=: 0 : 0 pc interact closeok; xywh 6 6 48 12;cc Value edit; xywh 6 18 48 12;cc increment button;cn "+"; xywh 6 30 48 12;cc random button;cn "?"; pas 6 6;pcenter; rem form end; )
interact_run=: 3 : 0
wd INTERACT wd 'set Value 0;' wd 'pshow;'
)
interact_close=: 3 : 0
wd'pclose'
)
interact_Value_button=: 3 : 0
wd 'set Value ' , ": {. 0 ". Value
)
interact_increment_button=: 3 : 0
wd 'set Value ' , ": 1 + {. 0 ". Value
)
interact_random_button=: 3 : 0
if. 0 = 2 wdquery 'Confirm';'Reset to random number?' do. wd 'set Value ' , ": ?100 end.
)</lang>
Note: I used an edit box for the value, and edit boxes do not get onChange events, so rejection of non-numeric values will be delayed until the use of a button (or pressing enter).
Example use:
<lang j>interact_run</lang>
Java
There are nice GUI editors in some IDEs (Netbeans has a notoriously good one), but this GUI was not built automatically, so it's a little easier to understand. <lang java>import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener;
import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField;
public class Interact extends JFrame{ final JTextField numberField; final JButton incButton, randButton;
public Interact(){ //stop the GUI threads when the user hits the X button setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
numberField = new JTextField(); incButton = new JButton("Increment"); randButton = new JButton("Random");
numberField.setText("0");//start at 0
//listen for button presses in the text field numberField.addKeyListener(new KeyListener(){ @Override public void keyTyped(KeyEvent e) { //if the entered character is not a digit if(!Character.isDigit(e.getKeyChar())){ //eat the event (i.e. stop it from being processed) e.consume(); } } @Override public void keyReleased(KeyEvent e){} @Override public void keyPressed(KeyEvent e){} });
//listen for button clicks on the increment button incButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { String text = numberField.getText(); if(text.isEmpty()){ numberField.setText("1"); }else{ numberField.setText((Long.valueOf(text) + 1) + ""); } } });
//listen for button clicks on the random button randButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { //show a dialog and if they answer "Yes" if(JOptionPane.showConfirmDialog(null, "Are you sure?") == JOptionPane.YES_OPTION){ //set the text field text to a random positive long numberField.setText(Long.toString((long)(Math.random() * Long.MAX_VALUE))); } } });
//arrange the components in a grid with 2 rows and 1 column setLayout(new GridLayout(2, 1));
//a secondary panel for arranging both buttons in one grid space in the window JPanel buttonPanel = new JPanel();
//the buttons are in a grid with 1 row and 2 columns buttonPanel.setLayout(new GridLayout(1, 2)); //add the buttons buttonPanel.add(incButton); buttonPanel.add(randButton);
//put the number field on top of the buttons add(numberField); add(buttonPanel); //size the window appropriately pack();
}
public static void main(String[] args){ new Interact().setVisible(true); } }</lang>
Liberty BASIC
Input Verification
<lang lb>nomainwin
textbox #demo.val, 20, 50, 90, 24 button #demo.inc, "Increment", [btnIncrement], UL, 20, 90, 90, 24 button #demo.rnd, "Random", [btnRandom], UL, 20, 120, 90, 24 open "Rosetta Task: GUI component interaction" for window as #demo #demo "trapclose [quit]" validNum$ = "0123456789." #demo.val 0
wait
[quit]
close #demo
end
[btnIncrement]
#demo.val "!contents? nVal$" nVal$ = trim$(nVal$) if left$(nVal$, 1) = "-" then neg = 1 nVal$ = mid$(nVal$, 2) else neg = 0 end if validNum = 1 nDecs = 0 for i = 1 to len(nVal$) if instr(validNum$, mid$(nVal$, i, 1)) = 0 then validNum = 0 end if if mid$(nVal$, i, 1) = "." then nDecs = nDecs + 1 end if next i if nDecs > 1 then validNum = 0 end if if neg = 1 then nVal$ = "-";nVal$ end if if validNum = 0 then notice nVal$;" does not appear to be a valid number. " + _ "(Commas are not allowed.)" else nVal = val(nVal$) nVal = nVal + 1 end if #demo.val nVal
wait
[btnRandom]
confirm "Reset value to random number";yn$ if yn$ = "yes" then nVal = int(rnd(1) * 100) + 1 #demo.val nVal end if
wait</lang>
Impossible to type non-numeric characters
<lang lb>nomainwin
stylebits #demo.val, _ES_NUMBER, 0, 0, 0 textbox #demo.val, 20, 50, 90, 24 button #demo.inc, "Increment", [btnIncrement], UL, 20, 90, 90, 24 button #demo.rnd, "Random", [btnRandom], UL, 20, 120, 90, 24 open "Rosetta Task: GUI component interaction" for window as #demo #demo "trapclose [quit]" #demo.val 0
wait
[quit]
close #demo
end
[btnIncrement]
#demo.val "!contents? nVal" nVal = nVal + 1 #demo.val nVal
wait
[btnRandom]
confirm "Reset value to random number";yn$ if yn$ = "yes" then nVal = int(rnd(1) * 100) + 1 #demo.val nVal end if
wait</lang>
Oz
Using Mozart's standard GUI library, building a small desktop application: <lang oz>declare
[QTk] = {Module.link ['x-oz://system/wp/QTk.ozf']}
proc {Main} MaxValue = 1000 NumberWidget GUI = lr( numberentry(init:1 min:0 max:MaxValue handle:NumberWidget) button(text:"Increase" action:proc {$} OldVal = {NumberWidget get($)} in {NumberWidget set(OldVal+1)} end) button(text:"Random" action:proc {$} if {Ask "Reset to random?"} then Rnd = {OS.rand} * MaxValue div {OS.randLimits _} in {NumberWidget set(Rnd)} end end) ) Window = {QTk.build GUI} in {Window show} end
fun {Ask Msg} Result Box = {QTk.build td(message(init:Msg) lr(button(text:"Yes" action:proc {$} Result=true {Box close} end) button(text:"No" action:proc {$} Result=false {Box close} end) ))} in {Box show} {Box wait} Result end
in
{Main}</lang>
As a web application, using the "Roads" web programming library. Connect your browser to http://localhost:8080/start after starting the program. <lang oz>declare
[Roads] = {Module.link ['x-ozlib://wmeyer/roads/Roads.ozf']}
MaxValue = 1000
fun {Start Session} {Page 0} end
fun {Page Val} html( body( %% numerical input with an HTML form local NewVal in form( {NumberInput Val NewVal} input(type:submit) method:post action:fun {$ _} {Page NewVal} end ) end %% link with button functionality a("Increase" href:fun {$ _} {Page Val+1} end) " " %% another "button-link" a("Random" href:fun {$ S} p("Reset to random? - " a("Yes" href:fun {$ _} Rnd = {OS.rand} * MaxValue div {OS.randLimits _} in {Page Rnd} end) " " a("No" href:fun {$ _} {Page Val} end) ) end) )) end
%% a "formlet", managing input of an integer value fun {NumberInput OldVal NewVal} input(type:text validate:int_in(0 MaxValue) value:{Int.toString OldVal} bind:proc {$ Str} NewVal = {String.toInt Str.escaped} end ) end
in
{Roads.registerFunction 'start' Start} {Roads.run}</lang>
PicoLisp
The standard PicoLisp GUI is HTTP based. Connect your browser to http://localhost:8080 after starting the following script. <lang PicoLisp>#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
(load "@ext.l" "@lib/http.l" "@lib/xhtml.l" "@lib/form.l")
(de start ()
(and (app) (zero *Number)) (action (html 0 "Increment" "lib.css" NIL (form NIL (gui '(+Var +NumField) '*Number 20 "Value") (gui '(+JS +Button) "increment" '(inc '*Number) ) (gui '(+Button) "random" '(ask "Reset to a random value?" (setq *Number (rand)) ) ) ) ) ) )
(server 8080 "@start") (wait)</lang>
PureBasic
<lang PureBasic>Enumeration
#StringGadget #Increment #Random
EndEnumeration
If OpenWindow(0,#PB_Ignore,#PB_Ignore,180,50,"PB-GUI",#PB_Window_SystemMenu)
StringGadget(#StringGadget,5,5,170,20,"",#PB_String_Numeric) ButtonGadget(#Increment,5,25,80,20, "Increment") ButtonGadget(#Random, 90,25,80,20, "Random") Repeat Event=WaitWindowEvent() If Event=#PB_Event_Gadget Select EventGadget() Case #Increment CurrentVal=Val(GetGadgetText(#StringGadget)) SetGadgetText(#StringGadget,Str(CurrentVal+1)) Case #Random Flag=#PB_MessageRequester_YesNo Answer=MessageRequester("Randomize","Are you sure?",Flag) If Answer=#PB_MessageRequester_Yes SetGadgetText(#StringGadget,Str(Random(#MAXLONG))) EndIf EndSelect EndIf Until Event=#PB_Event_CloseWindow CloseWindow(0)
EndIf</lang>
Ruby
Uses the Shoes library. <lang ruby>Shoes.app do
stack do @textbox = edit_line
@textbox.change do @textbox.text = @textbox.text.gsub(/[^\d]/, ) and alert "Input must be a number!" if @textbox.text !~ /^\d*$/ end
flow do button "Increment" do @textbox.text = @textbox.text.to_i + 1 end
button "Random" do @textbox.text = rand 5000 if confirm "Do you want a random number?" end end end
end</lang>
Tcl
<lang tcl>package require Tk
- --- Our data Model! ---###
- A single variable will do just fine
set field 0
- --- Lay out the GUI components in our View ---###
- We use the Ttk widget set here; it looks much better on Windows and OSX
- First, a quick hack to make things look even nicer
place [ttk::frame .bg] -relwidth 1 -relheight 1
- A labelled frame containing an entry field constrained to use numbers
pack [ttk::labelframe .val -text "Value"] pack [ttk::entry .val.ue -textvariable field \ -validate key -invalidcommand bell \ -validatecommand {string is integer %P}]
- Now, a pair of buttons
pack [ttk::button .inc -text "increment" -command step] pack [ttk::button .rnd -text "random" -command random]
- --- Now we define the behaviors, the Controller ---###
- How to respond to a click on the "increment" button
proc step {} {
global field incr field
}
- How to respond to a click on the "random" button
proc random {} {
global field if {[tk_messageBox -type yesno -parent . \
-message "Reset to random?"] eq "yes"} { set field [expr {int(rand() * 5000)}]
}
}</lang>
Visual Basic
In VB, windows are usually created in the IDE. The generated code is hidden from the user unless viewed outside of VB. For the sake of this task, I have included that code.
Note that there are other methods of validating the entered value. The method used is dependant on the program's requirements.
<lang vb>VERSION 5.00 Begin VB.Form Form1
Caption = "Form1" ClientHeight = 2265 ClientLeft = 60 ClientTop = 600 ClientWidth = 2175 LinkTopic = "Form1" ScaleHeight = 2265 ScaleWidth = 2175 StartUpPosition = 3 'Windows Default Begin VB.CommandButton cmdRnd Caption = "Random" Height = 495 Left = 120 TabIndex = 2 Top = 1680 Width = 1215 End Begin VB.CommandButton cmdInc Caption = "Increment" Height = 495 Left = 120 TabIndex = 1 Top = 1080 Width = 1215 End Begin VB.TextBox txtValue Height = 495 Left = 120 TabIndex = 0 Text = "0" Top = 240 Width = 1215 End
End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False '-----user-written code begins here; everything above this line is hidden in the GUI----- Private Sub Form_Load()
Randomize Timer
End Sub
Private Sub cmdRnd_Click()
If MsgBox("Random?", vbYesNo) Then txtValue.Text = Int(Rnd * 11)
End Sub
Private Sub cmdInc_Click()
If Val(txtValue.Text) < 10 Then txtValue.Text = Val(txtValue.Text) + 1
End Sub
Private Sub txtValue_KeyPress(KeyAscii As Integer)
Select Case KeyAscii Case 8, 43, 45, 48 To 57 'backspace, +, -, or number Case Else KeyAscii = 0 End Select
End Sub</lang>