Использование мнемоники кнопки не обновляет значение второй кнопки вращения

Я сделал образец Gtk::Spinbutton диалоговой программы, в которой пользователь может изменять значения ширины/высоты и видеть изменения (текст), выводимые на основной Gtk::Window

Главное окно

Я добавил две кнопки; Отмена и ОК с включенной мнемоникой set_use_underline()

введите здесь описание изображения

В целях тестирования я предполагаю, что пользователь изменяет оба значения. Программа работает нормально, когда я использую мышь, чтобы нажать кнопку ОК. Оба значения обновляются. Но когда для принятия изменений используется мнемоника кнопки OK (Alt + O), значение высоты или ширины не обновляется должным образом. Например, в поле «Ширина» я ввожу 1366, а в поле «Высота» ввожу 768, затем нажимаю Alt + O, чтобы активировать действие кнопки «ОК», обновляется ширина, но не высота. Вместо этого сохраняется предыдущее значение высоты, которое в начале программы равно 1.

Основной класс

  • Декларация
#ifndef WIDTHHEIGHT_H
#define WIDTHHEIGHT_H

class WidthHeight
{
    int width, height;

public:
    void set_width_core(int width = 1);
    int  get_width_core();
    void set_height_core(int height = 1);
    int  get_height_core();
};

#endif // WIDTHHEIGHT_H

  • Определение
#include "widthheight.h"

void WidthHeight::set_width_core(int width)
{
    this->width = width;
}

int WidthHeight::get_width_core()
{
    return width;
}

void WidthHeight::set_height_core(int height)
{
    this->height = height;
}

int WidthHeight::get_height_core()
{
    return height;
}

Диалоговый класс

  • Декларация
#ifndef WIDTHHEIGHTDIALOG_H
#define WIDTHHEIGHTDIALOG_H

#include <gtkmm/adjustment.h>
#include <gtkmm/dialog.h>
#include <gtkmm/label.h>
#include <gtkmm/spinbutton.h>

class WidthHeight;
class ExampleWindow;

class WidthHeightDialog : public Gtk::Dialog
{
    WidthHeight &core;
    ExampleWindow &window;
    Gtk::Label width, height;
    Glib::RefPtr<Gtk::Adjustment> w_adjustment, h_adjustment;
    Gtk::SpinButton *w_entry, *h_entry;

    enum response_id {
        REJECT,
        ACCEPT
    };

    void on_action_signal_response(int);

public:
    WidthHeightDialog(WidthHeight &, ExampleWindow &);
};

#endif // WIDTHHEIGHTDIALOG_H

  • Определение
#include <iostream>

#include "widthheightdialog.h"
#include "widthheight.h"
#include "examplewindow.h"

void WidthHeightDialog::on_action_signal_response(int id)
{
    switch (id)
    {
    case Gtk::RESPONSE_CLOSE:
    case response_id::REJECT:
        std::cout << "Canceled\n";
        break;
    case response_id::ACCEPT:
        std::cout << "OKayed\n";
        break;
    }

    core.set_width_core(w_entry->get_value_as_int());
    core.set_height_core(h_entry->get_value_as_int());
    window.refresh_label();
    std::cout << "Width: " << w_entry->get_value_as_int() << std::endl;
    std::cout << "Height: " << h_entry->get_value_as_int() << std::endl;

    hide();
}

WidthHeightDialog::WidthHeightDialog(WidthHeight &core, ExampleWindow &window)
    : Dialog("Change Width/Height value")
    , core(core)
    , window(window)
    , width("Width:")
    , height("Height:")
    , w_adjustment(Gtk::Adjustment::create(1, 1, 100000))
    , h_adjustment(Gtk::Adjustment::create(1, 1, 100000))
    , w_entry(manage(new Gtk::SpinButton(w_adjustment, 1, 0)))
    , h_entry(manage(new Gtk::SpinButton(h_adjustment, 1, 0)))
{
    auto box = get_content_area();
    box->add(width);
    box->add(*w_entry);
    box->add(height);
    box->add(*h_entry);

    box->show_all();

    add_button("_Cancel", response_id::REJECT)->set_use_underline();
    add_button("_OK"    , response_id::ACCEPT)->set_use_underline();

    signal_response().connect(sigc::mem_fun(*this, &WidthHeightDialog::on_action_signal_response));
}

Класс окна

  • Декларация
#ifndef EXAMPLEWINDOW_H
#define EXAMPLEWINDOW_H

#include <gtkmm/box.h>
#include <gtkmm/button.h>
#include <gtkmm/label.h>
#include <gtkmm/window.h>

#include "widthheight.h"
#include "widthheightdialog.h"

class ExampleWindow : public Gtk::Window
{
    Gtk::Box vbox;
    Gtk::Label label;
    Gtk::Button button;
    WidthHeight core;
    WidthHeightDialog dialog;

    void on_button_clicked();

public:
    ExampleWindow();
    void refresh_label();
};

#endif // EXAMPLEWINDOW_H

  • Определение
#include "examplewindow.h"

void ExampleWindow::on_button_clicked()
{
    dialog.show();

    dialog.present();
}

ExampleWindow::ExampleWindow()
    : vbox(Gtk::ORIENTATION_VERTICAL)
    , label("\n\tOutput printed on console...\t\n")
    , button("Change Width/Height value")
    , dialog(core, *this)
{
    set_title("Example");

    add(vbox);

    core.set_width_core();
    core.set_height_core();
    refresh_label();

    vbox.pack_start(label);
    label.set_line_wrap(true);
    label.set_selectable(true);

    vbox.pack_start(button);
    button.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_clicked));

    dialog.set_transient_for(*this);

    show_all_children();

    button.grab_focus();
}

void ExampleWindow::refresh_label()
{
    std::string width = "\n Width: " + std::to_string(core.get_width_core()) + "\n";
    std::string height = "Height: " + std::to_string(core.get_height_core()) + "\n";

    label.set_text(width + height);
}

Основной

#include <gtkmm/application.h>

#include "examplewindow.h"

int main()
{
    auto app = Gtk::Application::create("org.gtkmm.example");

    ExampleWindow window;

    return app->run(window);
}

person Keyikedalube Ndang    schedule 13.01.2021    source источник
comment
Ваш рабочий пример был очень полезным. Тем не менее, убедитесь, что ваши включенные заголовки имеют правильный регистр, иначе в некоторых системах (например, в Linux, где имена файлов чувствительны к регистру) он не будет собран.   -  person BobMorane    schedule 14.01.2021


Ответы (1)


Кажется, есть проблема с обновлением спинбоксов. Например, попробуйте следующее:

  1. Запустите приложение.
  2. Измените ширину, затем высоту.
  3. Щелкните внутри поля редактирования ширины.
  4. Нажмите Alt+O.

В этом случае вы увидите, что оба значения обновляются (точно так же, как и при нажатии). Я считаю, что при нажатии происходит то же самое, но с кнопкой. Щелчок по нему эквивалентен шагу 3 (т. е. передаче фокуса другому виджету), который, по-видимому, автоматически обновляет счетчик.

Чтобы обойти это, вы можете использовать метод Gtk::SpinButton::update() для принудительного обновление на спинбоксах. В вашем случае у вас будет:

void WidthHeightDialog::on_action_signal_response(int id)
{
    switch (id)
    {
    case Gtk::RESPONSE_CLOSE:
    case response_id::REJECT:
        std::cout << "Canceled\n";
        break;
    case response_id::ACCEPT:
        std::cout << "OKayed\n";
        break;
    }

    w_entry->update();  // Forces an update
    h_entry->update();  // Forces an update

    core.set_width_core(w_entry->get_value_as_int());
    core.set_height_core(h_entry->get_value_as_int());
    window.refresh_label();
    std::cout << "Width: " << w_entry->get_value_as_int() << std::endl;
    std::cout << "Height: " << h_entry->get_value_as_int() << std::endl;

    hide();
}

что гарантирует, что для обоих счетчиков, даже если пользователь не передает фокус другому виджету (и, следовательно, запускает автоматическое обновление последнего измененного счетчика), обновление все равно происходит.

person BobMorane    schedule 13.01.2021