I am working my way through the Vala GTK+3 tutorial provided by Elementary OS. I understand that this code:
var button_hello = new Gtk.Button.with_label ("Click me!");
button_hello.clicked.connect (() => {
button_hello.label = "Hello World!";
button_hello.set_sensitive (false);
});
uses a Lambda function to change the button's label when it's clicked. What I want to do is call this function instead:
void clicked_button(Gtk.Button sender) {
sender.label = "Clicked. Yippee!";
sender.set_sensitive(false);
}
I've tried this:
button.clicked.connect(clicked_button(button));
But I get this error from the Vala compile when I try to compile:
hello-packaging.vala:16.25-16.46: error: invocation of void method not allowed as expression
button.clicked.connect(clicked_button(button));
^^^^^^^^^^^^^^^^^^^^^^
Compilation failed: 1 error(s), 0 warning(s)
I'm new to both Vala and Linux so please be gentle but can someone point me in the right direction?
You need to pass a reference to the function, rather than the result of the function. So it should be:
button.clicked.connect (clicked_button);
When the button is clicked GTK+ will invoke the clicked_button function with the button as an argument.
The error message invocation of void method not allowed as expression is telling you you are calling (invoking) the method and it has no result (void). Adding parentheses, (), to the end of a function name invokes that function.
Managed to get it working. Here's the code in case others need it:
int main(string[] args) {
// Initialise GTK
Gtk.init(ref args);
// Configure our window
var window = new Gtk.Window();
window.set_default_size(350, 70);
window.title = "Hello Packaging App";
window.set_position(Gtk.WindowPosition.CENTER);
window.set_border_width(12);
window.destroy.connect(Gtk.main_quit);
// Create our button
var button = new Gtk.Button.with_label("Click Me!");
button.clicked.connect(clicked_button);
// Add the button to the window
window.add(button);
window.show_all();
// Start the main application loop
Gtk.main();
return 0;
}
// Handled the clicking of the button
void clicked_button(Gtk.Button sender) {
sender.label = "Clicked. Yippee!";
sender.set_sensitive(false);
}
In GXT (from Sencha) I am attempting to use a ProgressMessageBox to show the user that work is being done, but I am not seeing the message box until after all of the work is complete. Here is the code:
final ProgressMessageBox messageBox = new ProgressMessageBox("Task Description",
"Executing Task...");
messageBox.setProgressText("Calculating...");
messageBox.setPredefinedButtons();
messageBox.show();
for (int i = 0; i < 5; ++i) {
for (long l = 0l; l < 10000000000l; ++l) {
if (l == 12345l) {
MyUtil.info(60, "" + System.currentTimeMillis() / 1000);
}
}
messageBox.updateProgress((double)(i + 1) / 5, "{0}% Complete");
}
This code is in the SelectionHandler of a menu item. Obviously I am not actually just looping a few billion times in the "real" code, but when I perform the work that I want to execute I get the same result ... the message box is shown after all the work has been completed. I see the "info" messages (MyUtil#info is simply a wrapper around the GXT Info capability, which causes an info message to be displayed for the specified number of seconds) ... and on my machine, running the code shown, each message has a value that is about seven seconds greater than the previous message (but they all show up at the same time as the message box).
Is there something that I need to do after calling ProgressMessageBox#updateProgress to force the screen or message box to refresh?
I was able to get this to work by putting the task into a Scheduler#execute method. The example in the Sencha Explorer Demo uses a Timer, but since I don't know how long the execution will take I chose to use the Scheduler approach. Here is the relevant final code:
...
menuItem.addSelectionHandler(new SelectionHandler<Item>() {
#Override
public void onSelection(final SelectionEvent<Item> selectionEvent) {
final ProgressMessageBox messageBox = new ProgressMessageBox("Size All Columns", //
"Resizing Columns...");
messageBox.setProgressText("Calculating...");
// messageBox.setPredefinedButtons();
messageBox.show();
resizeNextColumn(messageBox,
_selectionModel instanceof CheckBoxSelectionModel ? 1 : 0,
_grid.getColumnModel().getColumnCount() - 1);
}
});
...
private void resizeNextColumn(final ProgressMessageBox messageBox,
final int columnIndex,
final int lastColumnIndex) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
resizeColumnToFit(columnIndex);
if (columnIndex == lastColumnIndex) {
messageBox.hide();
_grid.getView().refresh(true);
return;
}
messageBox.updateProgress((double)columnIndex / (lastColumnIndex + 1),
"{0}% Complete");
resizeNextColumn(messageBox, columnIndex + 1, lastColumnIndex);
}
});
}
One thing that didn't appear to work is the messageBox.setPredefinedButtons() call ... when I use this the progress bar in the message box doesn't update at all. I really didn't want an "OK" button on the dialog, but for now it'll have to do. I'm using 3.1.0 of GXT.
The tutorial here http://developer.gnome.org/gtk-tutorial/2.90/x542.html
shows how to set up the radio buttons, but neglects to tell you how to use them.
How do I then find which radio button is selected?
My solution:
Initialise radio buttons with:
rbutton1 = gtk_radio_button_new_with_label(NULL, "button1");
gtk_box_pack_start(GTK_BOX(rbutton_box), rbutton1, TRUE, TRUE, 0);
rbuttonGroup = gtk_radio_button_get_group(GTK_RADIO_BUTTON(rbutton1)); /*not sure what I'd use this line for currently though*/
rbutton2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rbutton1), "button 2");
gtk_box_pack_start(GTK_BOX(rbutton_box), rbutton2, TRUE, TRUE, 0);
rbutton3 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rbutton1), "button 3");
gtk_box_pack_start(GTK_BOX(rbutton_box), rbutton3, TRUE, TRUE, 0);
And update a variable telling you which radio button is selected with this method:
void checkRadioButtons()
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutton1))==TRUE) selectedRadioButton =1;
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutton2))==TRUE) selectedRadioButton =2;
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutton3))==TRUE) selectedRadioButton =3;
}
Google brought me here for python / pygtk / pygtk3 searches, so I hope its okay that I post a pygtk solution:
def _resolve_radio(self, master_radio):
active = next((
radio for radio in
master_radio.get_group()
if radio.get_active()
))
return active
This uses a generator to return the first (which should be the only) active radio box that is active.
This is how I do it.
GtkRadioButton * radio_button;
GtkRadioButton * radio_button1;
GtkRadioButton * radio_button2;
...
GSList * tmp_list = gtk_radio_button_get_group (radio_button);//Get the group of them.
GtkToggleButton *tmp_button = NULL;//Create a temp toggle button.
while (tmp_list)//As long as we didn't reach the end of the group.
{
tmp_button = tmp_list->data;//Get one of the buttons in the group.
tmp_list = tmp_list->next;//Next time we're going to check this one.
if (gtk_toggle_button_get_active(tmp_button))//Is this the one active?
break;//Yes.
tmp_button = NULL;//We've enumerated all of them, and none of them is active.
}
//Here. tmp_button holds the active one. NULL if none of them is active.
See the discussion here.
I don't know if they will add this function into it (seems not).
Here's how I suggest doing it:
void radio_button_selected (GtkWidget *widget, gpointer data)
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))
{
GSLIST *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
g_print ("Index = %i%\n", g_slist_index (group, widget));
}
}
You may connect to the GtkToggleButton::toggled signal instead. In the associated callback, you'll be able to update your variable. As for the call to gtk_radio_button_get_group, you only need it if you call gtk_radio_button_new_with_label instead of gtk_radio_button_new_with_label_with_widget, as specified in the tutorial you're refering to.
Let's create a serie of buttons :
for severity in levels:
radio = gtk.RadioButton(group=radioButtons, label=severity)
if severity == actualLevel:
radio.set_active(True)
hBox.pack_start(radio, True, True, 3)
radio.connect('toggled', self.radioButtonSelected, severity)
and all buttons are connected to the same handler :
def radioButtonSelected(self, button, currentSeverity):
# proceed with the task
# as you can see, button is passed by as argument by the event handler
# and you can, for example, get the button label :
labelReadFromButton = button.getLabel()
Use lambda expressions if you dont want to mess around with the annoying methods, still have to use connect though, but its alot easier to read:
Enum RadioValues { A, B, C, none };
RadioValues values = RadioValues.none; // only needed if you dont have an initially selected radio button
MyConstructor()
{
Build();
// asumming you have 3 radio buttons: radioA, radioB, radioC:
radioA.Toggled += (sender,e) => values = RadioValues.A;
radioB.Toggled += (sender,e) => values = RadioValues.B;
radioC.Toggled += (sender,e) => values = RadioValues.C;
}
and thats it, no methods to deal with, and you dont have to restrict yourself to just that either, you can also use an anonymous function if you need more flex--of course the next step after that is using methods. Unfortunately they didnt offer a simple .Checked property, my next suggestion is to override the radio button itself and chain a Checked property when it's toggled state is changed, emulating other frameworks like MFC, Qt, and Winforms... etc.
PS: I left out boilerplate code for simplicity's sake, which can make answers a bit more muddled and you probably just want the facts not a demonstration on whether or not I can properly call a constructor :)
My solution for GTKmm is quite easier,
You just have to call the function :
my_radio_button.get_active(); \n
This will return either 0 if its unactive or 1 if its active.
This is a demo code using Radio Buttons, where you can find how I find which radio button is selected:
#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/radiobutton.h>
#include <gtkmm/separator.h>
#include <gtkmm/application.h>
#include <iostream>
class ButtonWindow : public Gtk::Window
{
private:
//Child widgets:
Gtk::Box m_Box_Top, m_Box1, m_Box2;
Gtk::RadioButton m_RadioButton1, m_RadioButton2, m_RadioButton3;
Gtk::Separator m_Separator;
Gtk::Button m_Button_Close;
Gtk::RadioButton *m_SelectedButton{nullptr};
public:
ButtonWindow()
: m_Box_Top(Gtk::ORIENTATION_VERTICAL),
m_Box1(Gtk::ORIENTATION_VERTICAL, 15),
m_Box2(Gtk::ORIENTATION_VERTICAL, 0),
m_RadioButton1("button 1"),
m_RadioButton2("button 2"),
m_RadioButton3("button 3"),
m_Button_Close("close")
{
// Set title and border of the window
set_title("radio buttons");
set_border_width(0);
// Put radio buttons 2 and 3 in the same group as 1:
m_RadioButton2.join_group(m_RadioButton1);
m_RadioButton3.join_group(m_RadioButton1);
// Add outer box to the window (because the window
// can only contain a single widget)
add(m_Box_Top);
//Put the inner boxes and the separator in the outer box:
m_Box_Top.pack_start(m_Box1);
m_Box_Top.pack_start(m_Separator);
m_Box_Top.pack_start(m_Box2);
// Set the inner boxes' borders
m_Box1.set_border_width(20);
m_Box2.set_border_width(10);
// Put the radio buttons in Box1:
m_Box1.pack_start(m_RadioButton1);
m_Box1.pack_start(m_RadioButton2);
m_Box1.pack_start(m_RadioButton3);
// Put Close button in Box2:
m_Box2.pack_start(m_Button_Close);
// Connect the button signals:
#if 1 // Full C++11: (change this to #if 0 to use the traditional way)
m_RadioButton1.signal_clicked().connect([&]{on_radio_button_clicked(m_RadioButton1);});
m_RadioButton2.signal_clicked().connect([&]{on_radio_button_clicked(m_RadioButton2);});
m_RadioButton3.signal_clicked().connect([&]{on_radio_button_clicked(m_RadioButton3);});
m_Button_Close.signal_clicked().connect([&]{on_close_button_clicked();});
#else // Traditional:
m_RadioButton1.signal_clicked() // Full sigc
.connect(sigc::bind(sigc::mem_fun(*this, &ButtonWindow::on_radio_button_clicked),
sigc::ref(m_RadioButton1)));
m_RadioButton2.signal_clicked() // sigc && C++98
.connect(std::bind(sigc::mem_fun(*this, &ButtonWindow::on_radio_button_clicked),
std::ref(m_RadioButton2)));
m_RadioButton3.signal_clicked() // Full C++98
.connect(std::bind(&ButtonWindow::on_radio_button_clicked, this,
std::ref(m_RadioButton3)));
m_Button_Close.signal_clicked()
.connect(sigc::mem_fun(*this, &ButtonWindow::on_close_button_clicked));
#endif
// Set the second button active:
m_RadioButton2.set_active();
// Make the close button the default widget:
m_Button_Close.set_can_default();
m_Button_Close.grab_default();
// Show all children of the window:
show_all_children();
}
protected:
//Signal handlers:
void on_radio_button_clicked(Gtk::RadioButton& button)
{
if(m_SelectedButton != &button && button.get_active())
{
m_SelectedButton = &button;
std::cout << "Radio "<< m_SelectedButton->get_label() << " selected.\n";
}
}
void on_close_button_clicked()
{
hide(); // Close the application
}
};
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
ButtonWindow button;
//Shows the window and returns when it is closed.
return app->run(button);
}
I have a tabpanel with 3 tabs. One of the tabs has a table which draws a table with data from the database. But if new data is entered, after I select the tab I have to refresh the browser page to see the update.
I've added the following selection handler to the tabpanel:
tabpanel.addSelectionHandler(new SelectionHandler<Integer>()
{
public void onSelection(SelectionEvent<Integer> event)
{
int tabId = event.getSelectedItem();
Widget tabWidget = tabpanel.getWidget(tabId);
if (tabWidget != null)
{
//assumming that code to refresh will go here...
}
}
});
What can I do so that when a certain tab is selected then that tab will refresh?
Thanks so much in advance.
What you have done is correct. Just put your data access code in the commented area. So for example
int tabId = event.getSelectedItem();
// PSEUDO CODE
data = AsyncCallback.getData()
tabPanel.setWidget(tabId, new Widget(data)); // PSEUDO CODE
.Net Compact Framework
Scenario: User is on a screen. Device can't finds a printer and asks the user if they want to try again. If they click "No", the current screen is closed and they are returned to the parent menu screen. If they click the "No" button multiple times, the first click will be used by the No button and the next click will take effect once the screen has completed redrawing. (In effect clicking a menu item which then takes the user to another screen.)
I don't see a good place to put a wait cursor...there isn't much happening when the user clicks "No" except a form closing. But the CF framework is slow to redraw the screen.
Any ideas?
you can skip pending clicks by clearing the windows message queue with
Application.DoEvents();
We use the following custom Event class to solve your problem (preventing multiple clicks and showing a wait cursor if necessary):
using System;
using System.Windows.Forms;
public sealed class Event {
bool forwarding;
public event EventHandler Action;
void Forward (object o, EventArgs a) {
if ((Action != null) && (!forwarding)) {
forwarding = true;
Cursor cursor = Cursor.Current;
try {
Cursor.Current = Cursors.WaitCursor;
Action(o, a);
} finally {
Cursor.Current = cursor;
Application.DoEvents();
forwarding = false;
}
}
}
public EventHandler Handler {
get {
return new EventHandler(Forward);
}
}
}
You can verify that it works with the following example (Console outputs click only if HandleClick has terminated):
using System;
using System.Threading;
using System.Windows.Forms;
class Program {
static void HandleClick (object o, EventArgs a) {
Console.WriteLine("Click");
Thread.Sleep(1000);
}
static void Main () {
Form f = new Form();
Button b = new Button();
//b.Click += new EventHandler(HandleClick);
Event e = new Event();
e.Action += new EventHandler(HandleClick);
b.Click += e.Handler;
f.Controls.Add(b);
Application.Run(f);
}
}
To reproduce your problem change the above code as follows (Console outputs all clicks, with a delay):
b.Click += new EventHandler(HandleClick);
//Event e = new Event();
//e.Action += new EventHandler(HandleClick);
//b.Click += e.Handler;
The Event class can be used for every control exposing EventHandler events (Button, MenuItem, ListView, ...).
Regards,
tamberg
Random thoughts:
Disable the some of the controls on the parent dialog while a modal dialog is up. I do not believe that you can disable the entire form since it is the parent of the modal dialog.
Alternatively I would suggest using a Transparent control to catch the clicks but transparency is not supported on CF.
How many controls are on the parent dialog? I have not found CF.Net that slow in updating. Is there any chance that the dialog is overloaded and could be custom drawn faster that with sub controls?
override the DialogResult property and the Dispose method of the class to handle adding/remvoing a wait cursor.