Подкласс QLabel для отображения собственного индикатора кнопки наведения мыши

У меня есть QLabel с рамкой "StyledPanel, поднятая".
На нее можно щелкнуть, создав подкласс QLabel;

class InteractiveLabel(QtGui.QLabel):
    def __init__(self, parent):  
        QtGui.QLabel.__init__(self, parent)

    def mouseReleaseEvent(self, event):  
        self.emit(QtCore.SIGNAL('clicked()'))

Однако общее мнение состоит в том, что это "ящик" не так легко распознать как интерактивный.
В целях повышения удобства использования я хотел бы, чтобы "коробка" показывала, что на нее можно нажимать при наведении на нее указателя мыши.
> Очевидно, что реакцию на наведение мыши легко получить, подключив событие mouseHoverEvent.

Однако «индикатор кнопки» должен быть изначально унаследован, поскольку мое приложение Qt позволяет пользователю изменять стиль (из Windows XP, Windows 7, пластика, мотива, cde).

На этом изображении показан конкретный виджет (нижний правый угол) и желаемая эстетика mouseHover в двух разных стилях.

Изображение, показывающее

Когда указатель мыши наводится на "Box", я хотел бы, чтобы он реагировал так же, как поле со списком вверху, посередине.
("Ответ" эстетически нативен и происходит со всеми кнопками Qt, кроме "CDE" и «стили мотивов».).

Есть ли способ реализовать это с помощью PyQt4?
(Я полагаю, что ненативные решения будут включать QGradient и проверку нативного стиля, но это противно.)

ОБНОВЛЕНИЕ:
идея lol4t0 о QLabel над QPushButton.

Вот моя питоническая реализация с правильно работающими сигналами и соответствующей эстетикой кнопок. RichTextBox — это виджет, который вы встраиваете в программу.

from PyQt4 import QtCore, QtGui

class RichTextButton(QtGui.QPushButton):
    def __init__(self, parent=None):  
        QtGui.QPushButton.__init__(self, parent)
        self.UnitText = QtGui.QLabel(self)
        self.UnitText.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
        self.UnitText.setAlignment(QtCore.Qt.AlignCenter)
        self.UnitText.setMouseTracking(False)
        self.setLayout(QtGui.QVBoxLayout())
        self.layout().setMargin(0)
        self.layout().addWidget(self.UnitText)

Спасибо!


Спецификации:
— Python 2.7.2
— Windows 7
— PyQt4


person Anti Earth    schedule 22.01.2012    source источник
comment
Глупый вопрос, но если вам нужна заметно кликабельная метка, QPushButton именно то, что вам нужно. Вы можете поиграть со стилем кнопки (поднять/опустить, кое-что еще). Почему бы не использовать это?   -  person Mat    schedule 22.01.2012
comment
Резонный вопрос! Текст поля должен быть форматированным текстом. Если есть возможность установить форматированный текст на кнопку, то мои чеки действительно будут читаться! :|   -  person Anti Earth    schedule 22.01.2012
comment
Кроме того, как вы устанавливаете поднятие/опускание на QPushButton (у него нет QFrame... не так ли?)   -  person Anti Earth    schedule 23.01.2012


Ответы (2)


Смысл

Вы можете добавить QLabelнад QPushButton (сделать QLabel дочерним элементом QPushButton) и отображать форматированный текст в метке, а клики и декорации можно обрабатывать с помощью QPushButton

Эксперимент

Ну я C++ программист, но ничего сложного, надеюсь, вы поняли код

  • Реализация основной идеи:

    QLabel * label = new QLabel(pushButton);
    label->setText("<strong>sss</strong>");
    label->setAlignment(Qt::AlignCenter);
    label->setMouseTracking(false);
    pushButton->setLayout(new QVBoxLayout(pushButton));
    pushButton->layout()->setMargin(0);
    pushButton->layout()->addWidget(label);
    

    И это почти работает! Единственная глупая ошибка (или мое глобальное недоразумение) заключается в том, что когда вы нажимаете кнопку мышью, а затем отпускаете ее, она остается нажатой.

- Итак, похоже, нам нужно переопределить mouseReleaseEvent в нашем label, чтобы исправить проблему всегда нажимается:

Я почти уверен, что есть более элегантное решение, но мне лень его искать, поэтому я сделал следующее:

    class TransperentLabel: public QLabel
    {
    public:
        TransperentLabel(QWidget* parent):QLabel(parent) {}
    protected:
        void mouseReleaseEvent(QMouseEvent *ev)
        {
            /*
            QApplication::sendEvent(parent(), ev); -- does not help :(
            */
            static_cast<QPushButton*>(parent())->setDown(false);
            static_cast<QPushButton*>(parent())->click(); //fixing click signal issues
        }
    };

  • Как сказал @Roku, чтобы решить эту проблему, мы должны добавить

    label->setTextInteractionFlags(Qt::NoTextInteraction);
    
person Lol4t0    schedule 22.01.2012
comment
Когда я передаю pushButton конструктору label, я имею в виду, что сделал label дочерним элементом pushButton. А потом да, я сделал новый макет для pushButton и добавил к нему label - person Lol4t0; 22.01.2012
comment
Не могли бы вы объяснить нижний фрагмент кода словами? (Я вижу, вы подклассифицируете QLabel, но что именно вы выполняете в программе, когда срабатывает mouseReleaseEvent?). Спасибо! - person Anti Earth; 22.01.2012
comment
я переопределяю mouseReleaseEvent (как и вы), затем, вы помните, что parent моего label равно QPushButton, поэтому я привожу родителя из QObject в QPushButton и вызываю метод setDown(false), который отпускает кнопку - person Lol4t0; 22.01.2012
comment
Я обновил ОП своей реализацией. Просто сейчас возникли некоторые проблемы с сигнализацией, но я посмотрю, смогу ли я решить их самостоятельно. Спасибо за помощь! - person Anti Earth; 22.01.2012
comment
Добавление label->setTextInteractionFlags(Qt::NoTextInteraction); устраняет всегда нажатую проблему. - person ; 22.01.2012
comment
Чудесный. Вы двое, джентльмены, волшебники. - person Anti Earth; 23.01.2012
comment
@ Lol4t0, у меня есть некоторые улучшения для вашего метода здесь: stackoverflow.com/a/10860800/440168 - person k06a; 02.06.2012

@Lol4t0, у меня есть несколько улучшений для вашего метода...

Это мой заголовочный файл:

#ifndef QLABELEDPUSHBUTTON_H
#define QLABELEDPUSHBUTTON_H

#include <QPushButton>

class QLabel;

class QLabeledPushButton : public QPushButton
{
    Q_OBJECT

    QLabel * m_label;

public:
    QLabeledPushButton(QWidget * parent = 0);

    QString text() const;
    void setText(const QString & text);

protected:
    void resizeEvent(QResizeEvent * event);
};

#endif // QLABELEDPUSHBUTTON_H

И есть мой файл cpp:

#include <QLabel>
#include <QVBoxLayout>
#include <QResizeEvent>
#include "QLabeledPushButton.h"

QLabeledPushButton::QLabeledPushButton(QWidget * parent)
    : QPushButton(parent)
    , m_label(new QLabel(this))
{
    m_label->setWordWrap(true);
    m_label->setMouseTracking(false);
    m_label->setAlignment(Qt::AlignCenter);
    m_label->setTextInteractionFlags(Qt::NoTextInteraction);
    m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
}

QString QLabeledPushButton::text() const
{
    return m_label->text();
}

void QLabeledPushButton::setText(const QString & text)
{
    m_label->setText(text);
}

void QLabeledPushButton::resizeEvent(QResizeEvent * event)
{
    if (width()-8 < m_label->sizeHint().width())
        setMinimumWidth(event->oldSize().width());
    if (height()-8 < m_label->sizeHint().height())
        setMinimumHeight(event->oldSize().height());

    m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
}

Таким образом, текст на QLabel всегда виден. QPushButton не может быть слишком маленьким, чтобы скрыть часть текста. Я думаю, что этот способ более удобен в использовании...

person k06a    schedule 02.06.2012
comment
Очень разумно, если бы я повторно использовал виджет. Однако я использую фиксированные позиции, так что это не имеет большого значения. Спасибо хоть! - person Anti Earth; 03.06.2012