Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: gil9red от Февраль 17, 2013, 00:50



Название: QPushButton::setChecked() и вызов меню
Отправлено: gil9red от Февраль 17, 2013, 00:50
Здравствуйте!
Помогите разобраться и доделать :)

Задание:
Создать кнопку. При нажатии на нее она помечается (checked = true) и появляется меню.
Меню и функцию его появления сделать самому. При повторном нажатии на кнопку, меню исчезает и исчезает метка на кнопке (checked = false). Меню также исчезает, если оно теряет фокус. Если у меню нет фокуса, метка с кнопки также исчезает.


В общем, сделал почти все, вот только проблемка возникла.

Нажатие на кнопку вызывает этот слот:
Код:
void showPopup()
{
    bool checked = pButtonShowHideDropDownMenu->isChecked();

    QPoint pos = pButtonShowHideDropDownMenu->mapToGlobal(QPoint(0,
                                                  pButtonApply->height()));
    dropDownMenu->move(pos);

    dropDownMenu->setVisible(checked);
}
т.е. получаем состояние кнопки (checked) и взависимости от него показываем/прячем наш виджет-меню с флагом Qt::Popup

Осталось сделать так чтобы, при исчезновении меню кнопка перестала быть помеченной.

Переопределил я у виджета-меню событие исчезновения (hideEvent()), в нем добавил генерацию сигнала. Когда сигнал отлавливается, вызывается слот с строкой:
Код:
pButtonShowHideDropDownMenu->setChecked(false);

Теперь нажатие на кнопку, вызывает меню, а повторное нажатие, прячет и снова его показывает
Если убрать строку
Код:
pButtonShowHideDropDownMenu->setChecked(false);
, то такого безобразия нет

Как сделать такое же поведение кнопки как и в QComboBox?

Спасибо :)


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: Bepec от Февраль 17, 2013, 00:52
Ты скорее всего подцепил слот свой на изменение состояния кнопки, а не на нажатие :)

Собственно ты этой строкой снова его вызываешь. Чудом не попадая в рекурсию :D


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: gil9red от Февраль 17, 2013, 00:56
слот поставил на сигнал clicked()


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: gil9red от Февраль 17, 2013, 01:10
Минимально компилируемый код:

h:
Код:
class UDropDownMenu: public QWidget
{
    Q_OBJECT

public:
    UDropDownMenu(QWidget *parent = 0)
    {
        setWindowFlags(Qt::Popup);

        gridLayout = new QGridLayout();

        setLayout(gridLayout);
    }

private:
    QGridLayout *gridLayout;

signals:
    void iHide();

protected:
    void paintEvent(QPaintEvent *event)
    {
        QWidget::paintEvent(event);

        QPainter painter(this);

        QPen pen;
        pen.setWidth(2);
        painter.setPen(pen);

        painter.drawRect(rect());
    }

    void hideEvent(QHideEvent *)
    {
        emit iHide();
    }
};

class UComboBoxButton: public QWidget
{
    Q_OBJECT   

public:
    UComboBoxButton(QWidget *parent = 0);

private:
    void createGUI();

private:
    QPushButton *pButtonShowHideDropDownMenu;
    UDropDownMenu *dropDownMenu;

public slots:
    void showPopup();

private slots:
    void dropDownMenuHide();
};

cpp:
Код:
/// PUBLIC
UComboBoxButton::UComboBoxButton(QWidget *parent)
    : QWidget(parent)
{
    createGUI();
}

/// PRIVATE
void UComboBoxButton::createGUI()
{
    QHBoxLayout *hBoxLayoutMain = new QHBoxLayout();

    dropDownMenu = new UDropDownMenu();
    connect(dropDownMenu, SIGNAL(iHide()),
            this, SLOT(dropDownMenuHide()));

    pButtonShowHideDropDownMenu = new QPushButton();
    pButtonShowHideDropDownMenu->setCheckable(true);
    pButtonShowHideDropDownMenu->setFixedSize(20, 20);

    connect(pButtonShowHideDropDownMenu, SIGNAL(clicked()),
            this, SLOT(showPopup()));

    hBoxLayoutMain->addWidget(pButtonShowHideDropDownMenu);
    hBoxLayoutMain->setSpacing(0);

    setLayout(hBoxLayoutMain);
}

/// PUBLIC SLOTS
void UComboBoxButton::showPopup()
{
    QPushButton *pButton = pButtonShowHideDropDownMenu;   

    QPoint pos = pButton->mapToGlobal(QPoint(0,
                                                  pButton->height()));

    dropDownMenu->move(pos);

    bool checked = pButton->isChecked();
    dropDownMenu->setVisible(checked);
}

/// PRIVATE SLOTS
void UComboBoxButton::dropDownMenuHide()
{
    QPushButton *pButton = pButtonShowHideDropDownMenu;
    pButton->setChecked(false);
}


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: Bepec от Февраль 17, 2013, 10:33
Осмелюсь спросить - а запускать то его как? :D

update:
Красотааа, а инклуды наверняка не нужны :D

update:
Проблему увидел, пока думаю. Там у тебя кнопка при потере фокуса с меню твоего испускает toggled. Пытаюсь найти что да как.

update:
Проблема банальна.

Код:
bool checked = pButton->isChecked(); // всегда равняется true


Выглядит лог примерно так
Цитировать
toggled true  - сигнал изменения состояния кнопки
button true   - твоя проверка, приведённая выше
click            - сигнал о нажатии кнопки (приходит позже, ибо подключён после твоего слота)
// - вот тут появляется твоё меню, далее я теряю фокус с меню (тыкаю на заголовок окна)
toggled false - сигнал изменения состоянии кнопки (pButton->setChecked(false);)

Вот и всё. Неправильный алгоритм просто.

update: Ещё упрощу:
Теперь нажатие на кнопку, вызывает меню, а повторное нажатие, прячет и снова его показывает
Если убрать строку
Код:
pButtonShowHideDropDownMenu->setChecked(false);
, то такого безобразия нет

Анализируем твой вопрос.
Алгоритм:
Первое нажатие:
clicked pushButton: Нажатие на кнопку
                           Проверка условий (всегда true, как я уже писал)
                           Вызов меню

Повторное нажатие
clicked pushButton: Переводим фокус с меню на кнопку (при повторном нажатии)
                           Меню исчезает
                           Проходит сигнал нажатия кнопки
                           Проверка условий (всегда true, как я уже писал)
                           Появление меню :)


PS и да, в следующий раз лучше уж проект выложи. Со всеми main/include. :)


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: GreatSnake от Февраль 17, 2013, 15:17
Создать кнопку. При нажатии на нее она помечается (checked = true) и появляется меню.
Меню и функцию его появления сделать самому. При повторном нажатии на кнопку, меню исчезает и исчезает метка на кнопке (checked = false). Меню также исчезает, если оно теряет фокус. Если у меню нет фокуса, метка с кнопки также исчезает.

Задача как минимум странная.
Во-первых, меню при своём появлении захватывает и мышь и клавиатуру - нажать кнопку не получится пока меню не будет спрятано.
Во-вторых, очень сильно попахивает изобретением велосипеда ибо QToolButton имеет нужную функциональность. См. QToolButton::setPopupMode().


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: gil9red от Февраль 17, 2013, 15:50
Верес, покажите что нужно исправить в алгоритме?


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: Bepec от Февраль 17, 2013, 16:15
Омм... Используй не свойство кнопки, а собственный флаг,как вариант. Честно - лень думать :D


Название: Re: QPushButton::setChecked() и вызов меню
Отправлено: gil9red от Февраль 17, 2013, 21:31
Решил воспользоваться советом GreatSnake, и реализовать через QToolButton.