Gtk::Button signals: pressed() released()

Hi
As far as I can see the Gtk::Button used to have pressed() and released() signals:

But in gtk4 I can only find clicked() and activated() signals:

could you please tell me what replaces the deprecated signals pressed() and released()?
Thx

Nothing. You should not have used those signals and methods in the first place: they were ever only useful if you implemented a class that derived from GtkButton and wanted to deal with button states.

The real question is: what are you trying to achieve?

Thx for the quick reply!
I want to set button press as the start of an action and release to stop the action.
I’m using gtkmm, if needed I can create a class that derives from Gtk::Button.
Can you give me an example of using button states ?

1 Like

Then don’t use GtkButton: use GtkToggleButton. That’s what it’s for.

Do you mean toggled signal?
It’s slightly different… Are there widgets that emit press and release signals?

No: I mean use a GtkToggleButton widget. You start and stop the action when the button is toggled.

Or you mean: you have to keep a button pressed to perform the action? In that case, you don’t want a GtkButton at all. Use a custom widget with a GtkGestureClick that draws itself in an active state when the gesture is pressed.

3 Likes

Just a note. I had the exact same problem. I needed a kind of “fire button” to allow manual timing of a very short or longer activation of an action.

The trick even non ideal working for me was to add a icon to the button and connect a controller to the icon and then I was able to get the pressed/released signal via the icon.

Downside is you have to click on the icon. If you miss out and hit the edge of the button only the button gets the click.

So it’s a little a hack to save my world without redesigning the nice button appearance.

Read also here:

THX!!! What do you mean by “icon” ? Which Gtk class? IconPaintable? DragIcon?
I get release signal ONLY when I connect the GtkGestureClick to a label inside my button.
I need an image though, and didn’t find a way to connect an image to Gtk Label.

With Icon I mean simply a button with a iconic symbol. Stock or custom. Usually a svg:

pushwid = gtk_button_new_from_icon_name ("media-seek-forward-symbolic");
  gtk_box_append (GTK_BOX (box), pushwid);
  gesture = gtk_gesture_click_new ();
  g_signal_connect (gesture, "pressed", G_CALLBACK (wid_pressed), "GTK-BUTTON-SEEK");
  g_signal_connect (gesture, "released", G_CALLBACK (wid_released), "GTK-BUTTON-SEEK");
  g_signal_connect (gesture, "stopped", G_CALLBACK (wid_stopped), "GTK-BUTTON-SEEK");
  g_signal_connect (pushwid, "clicked", G_CALLBACK (wid_clicked), "GTK-BUTTON-SEEK");
  if (gtk_button_get_child (GTK_BUTTON (pushwid))){
    g_message ("HAS CHILD");
    gtk_widget_add_controller (gtk_button_get_child (GTK_BUTTON (pushwid)), GTK_EVENT_CONTROLLER (gesture));
  }else
    gtk_widget_add_controller (pushwid, GTK_EVENT_CONTROLLER (gesture));
}

THX!!
I still don’t understand, I can set the color of the button on press like this:
#my-button:active
{
background-image: image(aqua);
}
this causes the button to change color on press and go back to the original color on release.
Why can’t I listen to the “active” signal?

I incorporated this in my cpp code, but I only get pressed signal, I don’t get released signal :frowning:

Sorry, my bad – mixed up the code pasting… this was the dysfunctional demo version with handler on the button. Handler must connect to the icon!

See this code (from my large project) and find the support code for (line 624) and the related helpers above:

“GtkWidget* grid_add_fire_icon_button (const gchar* icon_name,
GCallback pressed_cb=NULL, gpointer pressed_cb_data=NULL,
GCallback released_cb=NULL, gpointer released_cb_data=NULL,
const char *tooltip=NULL,
int bwx=1){…}”

here:

PS: it’s good to know that I am not alone with having a need for a bit more fine grained control than a very basic GUI may provide. I understand totally and support to create a clean and solid GUI, but a few things I simply do not agree with. It won’t hurt any thing to give the app developer hands on the basic pushed (MB down on button) and released signals – in addition to the regular “clicked” or even “double clicked” (do we have that?) signals which certainly are the most normal signals been required.

From the button code I dug into a bit and eventually gave up on… I see the pushed signal been absorbed and internally used for all the fancy cool renderings… fine. But it certainly could be exposed so I do not need to create either my own button widget or do some odd (imperfect, I know) hacks as above.

-P

@pyzahl your code helped a great deal, thx!!!

In conclusion: I registered to press and release signals via GestureClick controller, but I only get press event.
Is there a bug with release event? I would appreciate it if you checked. Here’s my code:

class ExampleWindow : public Gtk::Window
{
public:
    ExampleWindow(const Glib::RefPtr<Gtk::Application>& );
    virtual ~ExampleWindow();
     void on_button_pressed(int n_press, double x, double y);
     void on_button_released(int n_press, double x, double y);

 private:
     Gtk::Box m_box;
     Gtk::Button m_button;
     Gtk::Label m_label;

    Glib::RefPtr<Gtk::GestureClick> m_controller;

    double m_button_pressed_x;
    double m_button_pressed_y;
    bool m_button_pressed_called = false;
};

ExampleWindow::ExampleWindow(const Glib::RefPtr<Gtk::Application>&)
{
    set_title("Popover Example");
    set_default_size(500, -1);

    m_label.set_text("Label");
    m_button.set_child(m_label);
    m_box.append(m_button);
    set_child(m_box);

    m_controller = Gtk::GestureClick::create();
    m_controller->signal_pressed().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_pressed));
    m_controller->signal_released().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_released));
    m_button.add_controller(m_controller);
}

 ExampleWindow::~ExampleWindow() {}

void ExampleWindow::on_button_pressed(int, double x, double y)
{
    m_button_pressed_x = x;
    m_button_pressed_y = y;
    m_button_pressed_called = true;
    g_message ("Button Pressed\n");
}

void ExampleWindow::on_button_released(int, double, double)
{
    m_button_pressed_called = false;
    g_message ("Button Released\n");
}

int main(int argc, char* argv[])
{
    auto app = Gtk::Application::create("org.gtkmm.example");

    // Shows the window and returns when it is closed.
    return app->make_window_and_run<ExampleWindow>(argc, argv, app);
}

No, it’s not a bug. GtkButton already has an event controller that is used to handle pressed/release, and will take over the event sequences. Adding another event controller is not going to work. That’s why @pyzahl added an icon inside the button, and used an event controller on it.

If you’re taking over what GtkButton is doing, then I strongly recommend you write your own button-like widget—just like I suggested you last week.

Correct as Bassi said – you must put a icon (or some other widget possibly) “on” the button child to have access to the original undisturbed/filtered events! As I said,it’s a bit a hack… but works for me. And yes if you click at the button “edge” missing the icon you won’t get a signal even the button “activates”.

You did not create your own widget: you derived from GtkButton. This means you get all the behaviour and functionality encoded by GtkButton—including the fact that you cannot override the event controllers that GtkButton uses.

You have to write your own widget, i.e. derive from GtkWidget.

Same results… Do I need to override anything else? Is the icon still necessary?

class PressButton : public Gtk::Widget
{
public:
PressButton() = default;
virtual ~PressButton()
{
_button.unparent();
}
void Init(const Glib::ustring& icon)
{
_button.set_parent(*this);
_button.set_icon_name(icon);
_controller = Gtk::GestureClick::create();
_connectionPress = _controller->signal_pressed().connect(sigc::mem_fun(*this, &PressButton::OnPressed));
_connectionRelease = _controller->signal_released().connect(sigc::mem_fun(*this, &PressButton::OnReleased));
add_controller(_controller);
}

virtual void OnPressed(int, double, double)
{
    _isPressed = true;
    g_message("Button Pressed\n");
}
virtual void OnReleased(int, double, double)
{
    _isPressed = false;
    g_message("Button Released\n");
}

bool IsPressed() const
{
    return _isPressed;
}

private:
Gtk::Button _button;
Glib::RefPtrGtk::GestureClick _controller;
sigc::connection _connectionPress;
sigc::connection _connectionRelease;
bool _isPressed = false;

protected:
Gtk::SizeRequestMode get_request_mode_vfunc() const override
{
return Gtk::SizeRequestMode::HEIGHT_FOR_WIDTH;
}
void measure_vfunc(Gtk::Orientation orientation, int for_size, int& minimum, int& natural, int& minimum_baseline,
int& natural_baseline) const override
{
_button.measure(orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
}
void size_allocate_vfunc(int width, int height, int baseline) override
{
Gtk::Allocation child_allocation;
child_allocation.set_x(0);
child_allocation.set_y(0);
child_allocation.set_width(width);
child_allocation.set_height(height);
_button.size_allocate(child_allocation, baseline);
}
};

////////////////////////////////
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow(const Glib::RefPtrGtk::Application&);
virtual ~ExampleWindow();

private:
Gtk::Box m_box;
PressButton m_button;
};

ExampleWindow::ExampleWindow(const Glib::RefPtrGtk::Application&)
{
set_title(“Popover Example”);
set_default_size(500, -1);

m_box.append(m_button);
set_child(m_box);
m_button.Init("media-seek-forward-symbolic");
}

ExampleWindow::~ExampleWindow() {}

int main(int argc, char* argv[])
{
auto app = Gtk::Application::create(“org.gtkmm.example”);
return app->make_window_and_run(argc, argv, app);
}

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.