如何确保小部件上的两个标签之一并排获得focusInEvent?
Posted
技术标签:
【中文标题】如何确保小部件上的两个标签之一并排获得focusInEvent?【英文标题】:How to ensure one of two labels side-by-side on a widget getting focusInEvent? 【发布时间】:2021-02-17 22:54:42 【问题描述】:这里的代码创建了两个在 MDI 区域中以选项卡方式查看的小部件。每个小部件都包含两个标签。用户可以通过 Ctrl+Tab 在这两个小部件之间切换。当小部件是 Ctrl+tab 时,如何确保左标签获得 focusInEvent()?
我已经在代码中尝试了 activateWindow() 和 raise()。它们似乎没有区别。
我试图在这些小部件中只使用一个标签 - focusInEvent() 发生没有任何问题。当这些小部件中有两个或多个标签时(如代码中所示),Ctrl+tab 有时(但不总是)会触发左侧标签上的 focusInEvent,这反过来又会触发 MouseMoveEvent 以在鼠标位于左标签 - 如果您将鼠标放在左侧并多次按 Ctrl+tab 可以观察到这一点:有时工具提示不显示。
如果第二个标签是由QLabel *lbl2 = new QLabel;
创建的,则focusInEvent() 也会发生在第一个标签上,没有问题。
#include <QtCore>
#include <QtWidgets>
#include <QApplication>
#include <QMainWindow>
#include <QMouseEvent>
#include <QEvent>
#include <QGridLayout>
class MyLabel : public QLabel
public:
MyLabel(QWidget*parent = nullptr) : QLabel(parent)
setMouseTracking(true);
setFocusPolicy(Qt::FocusPolicy::StrongFocus);
setWindowFlag(Qt::ToolTip);
protected:
virtual void focusInEvent(QFocusEvent *ev) override
static int count;
qDebug() << __PRETTY_FUNCTION__ << " count: " << ++count;
QPoint posGlabal = QCursor::pos();
QPoint pos = this->mapFromGlobal(posGlabal);
if(this->rect().contains(pos))
// I want the label show a tooltip by mouseMoveEvent, when it is Ctrl+Tab on, without moving mouse
QMouseEvent* evt = new QMouseEvent(QEvent::MouseMove, QPointF(pos), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QCoreApplication::postEvent(this,evt);
QLabel::focusInEvent(ev);
virtual void mouseMoveEvent(QMouseEvent *ev) override
QString msg(QString::number(ev->pos().x()) +", " +QString::number(ev->pos().y()));
QToolTip::showText(ev->globalPos(), msg);
QLabel::mouseMoveEvent(ev);
;
class MyWidget : public QWidget
public:
MyWidget(QWidget *parent=nullptr) : QWidget(parent)
QGridLayout *layout = new QGridLayout;
// First label on left... I want it to show tooptip when Ctrl+Tab on if mouse on it (without moving mouse)
MyLabel *lbl1 = new MyLabel;
lbl1->setStyleSheet("QLabel background-color : green;");
layout->addWidget(lbl1, 0, 0);
// second label
MyLabel *lbl2 = new MyLabel;
//QLabel *lbl2 = new QLabel; // if I use this instead, no problem getting the tooltip on the left label.
lbl2->setStyleSheet("QLabel background-color : blue;");
layout->addWidget(lbl2, 0, 1);
// I want the left label to get focusInEvent()
// So I added these two lines in.
// But they do NOT make differences
lbl1->activateWindow();
lbl1->raise();
setLayout(layout);
;
class MainWindow : public QMainWindow
public:
MainWindow(QWidget *parent = nullptr)
: QMainWindow(parent)
QMdiArea *mdiArea = new QMdiArea;
this->setCentralWidget(mdiArea);
mdiArea->setViewMode(QMdiArea::TabbedView);
MyWidget *w1 = new MyWidget; w1->setWindowTitle("w1");
mdiArea->addSubWindow(w1);
MyWidget *w2 = new MyWidget; w2->setWindowTitle("w2");
mdiArea->addSubWindow(w2);
;
int main(int argc, char *argv[])
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
【问题讨论】:
【参考方案1】:我只进行了一些更改以帮助我调试您的问题。
我将 QMdiArea::subWindowActivated()
连接到 MyWidget 中的一个新插槽,该插槽将焦点设置到左侧标签。
我觉得这有点像 hack,但你应该能够改进我的想法。
#include <QtCore>
#include <QtWidgets>
#include <QApplication>
#include <QMainWindow>
#include <QMouseEvent>
#include <QEvent>
#include <QGridLayout>
class MyLabel : public QLabel
public:
MyLabel(const QString &name, QWidget*parent = nullptr)
: QLabel(parent)
, m_name(name)
setMouseTracking(true);
setFocusPolicy(Qt::FocusPolicy::StrongFocus);
setWindowFlag(Qt::ToolTip);
QString name() const return m_name;
protected:
virtual void focusInEvent(QFocusEvent *ev) override
static int count;
qDebug() << __PRETTY_FUNCTION__ << m_name << " count: " << ++count;
QPoint posGlabal = QCursor::pos();
QPoint pos = this->mapFromGlobal(posGlabal);
if(this->rect().contains(pos))
// I want the label show a tooltip by mouseMoveEvent, when it is Ctrl+Tab on, without moving mouse
QMouseEvent* evt = new QMouseEvent(QEvent::MouseMove, QPointF(pos), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QCoreApplication::postEvent(this,evt);
QLabel::focusInEvent(ev);
virtual void mouseMoveEvent(QMouseEvent *ev) override
QString msg(QString::number(ev->pos().x()) +", " +QString::number(ev->pos().y()));
QToolTip::showText(ev->globalPos(), msg);
QLabel::mouseMoveEvent(ev);
private:
QString m_name;
;
class MyWidget : public QWidget
public:
MyWidget(const QString &nameLeft, const QString &colorLeft, const QString &nameRight, const QString &colorRight, QWidget *parent=nullptr)
: QWidget(parent)
, lbl1(nameLeft)
, lbl2(nameRight)
QGridLayout *layout = new QGridLayout;
// First label on left... I want it to show tooptip when Ctrl+Tab on if mouse on it (without moving mouse)
lbl1.setStyleSheet(QString("QLabel background-color : %1;").arg(colorLeft));
layout->addWidget(&lbl1, 0, 0);
// second label
//QLabel *lbl2 = new QLabel; // if I use this instead, no problem getting the tooltip on the left label.
lbl2.setStyleSheet(QString("QLabel background-color : %1;").arg(colorRight));
layout->addWidget(&lbl2, 0, 1);
setLayout(layout);
// ----------------------------------------------------------------
public slots:
// The new slot that looks for the left label and sets the focus on it
void onSubWindowActivated(QMdiSubWindow *window)
auto lbl = window->findChild<MyLabel *>(lbl1.objectName());
// The events must be filtered, otherwise they'll trigger each other to death
if (lbl == nullptr)
return;
lbl->setFocus();
// ----------------------------------------------------------------
private:
MyLabel lbl1;
MyLabel lbl2;
;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
QMdiArea *mdiArea = new QMdiArea;
this->setCentralWidget(mdiArea);
mdiArea->setViewMode(QMdiArea::TabbedView);
MyWidget *w1 = new MyWidget("w1_L", "green", "w1_R", "blue");
w1->setWindowTitle("w1");
mdiArea->addSubWindow(w1);
// ----------------------------------------------------------------
connect(mdiArea, &QMdiArea::subWindowActivated,
w1, &MyWidget::onSubWindowActivated);
// ----------------------------------------------------------------
MyWidget *w2 = new MyWidget("w2_L", "yellow", "w2_R", "red");
w2->setWindowTitle("w2");
mdiArea->addSubWindow(w2);
// ----------------------------------------------------------------
connect(mdiArea, &QMdiArea::subWindowActivated,
w2, &MyWidget::onSubWindowActivated);
// ----------------------------------------------------------------
这里是QMdiArea::subWindowActivated()
的官方文档https://doc.qt.io/qt-5/qmdiarea.html#subWindowActivated
【讨论】:
以上是关于如何确保小部件上的两个标签之一并排获得focusInEvent?的主要内容,如果未能解决你的问题,请参考以下文章
如何在我的 Twitter 克隆中并排设置侧边栏、Feed 和小部件?