2012-12-28 44 views
6

我想强调一个QFrame,如果它的一个子控件具有焦点(以便用户知道到哪里寻找使用的东西光标;-)如何在子部件具有焦点时更改父部件的背景?

沿

ui->frame->setFocusPolicy(Qt::StrongFocus); 
ui->frame->setStyleSheet("QFrame:focus {background-color: #FFFFCC;}"); 

突出显示QFrame,当我点击它时,但是一旦它的一个子窗口小部件被选中,它就失去它的焦点。

可能的方法:

  • 我可以connect()QApplication::focusChanged(old,now)和检查每一个新的对象,如果它是我的QFrame的孩子,但是这就会变得混乱。

  • 我还可以每个子类子构件和重新实现focusInEvent()/focusOutEvent()并就反应,但有很多不同的小部件,这也是很多工作。

有没有更优雅的解决方案?

回答

7

那么,你可以扩展QFrame让它监听它的子部件的焦点变化。 或者您也可以在儿童小部件上安装事件过滤器,以捕获QFocusEvent

下面是一个例子:

MyFrame.h

#ifndef MYFRAME_H 
#define MYFRAME_H 

#include <QFrame> 

class MyFrame : public QFrame 
{ 
    Q_OBJECT 

public: 

    explicit MyFrame(QWidget* parent = 0, Qt::WindowFlags f = 0); 

    void hookChildrenWidgetsFocus(); 

protected: 

    bool eventFilter(QObject *object, QEvent *event); 

private: 

    QString m_originalStyleSheet; 
}; 

#endif // MYFRAME_H 

MyFrame.cpp

#include <QEvent> 
#include "MyFrame.h" 

MyFrame::MyFrame(QWidget *parent, Qt::WindowFlags f) 
    : QFrame(parent, f) 
{ 
    m_originalStyleSheet = styleSheet(); 
} 

void MyFrame::hookChildrenWidgetsFocus() 
{ 
    foreach (QObject *child, children()) { 
     if (child->isWidgetType()) { 
      child->installEventFilter(this); 
     } 
    } 
} 

bool MyFrame::eventFilter(QObject *object, QEvent *event) 
{ 
    if (event->type() == QEvent::FocusIn) { 
     setStyleSheet("background-color: #FFFFCC;"); 
    } else if (event->type() == QEvent::FocusOut) { 
     setStyleSheet(m_originalStyleSheet); 
    } 

    return QObject::eventFilter(object, event); 
} 

MainWindow.cpp

#include <QHBoxLayout> 
#include <QVBoxLayout> 
#include <QLineEdit> 
#include "MyFrame.h" 
#include "mainwindow.h" 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent) 
{ 
    setWindowTitle(tr("Test")); 

    MyFrame *frame1 = new MyFrame(this); 
    frame1->setLayout(new QVBoxLayout()); 
    frame1->layout()->addWidget(new QLineEdit()); 
    frame1->layout()->addWidget(new QLineEdit()); 
    frame1->layout()->addWidget(new QLineEdit()); 
    frame1->hookChildrenWidgetsFocus(); 

    MyFrame *frame2 = new MyFrame(this); 
    frame2->setLayout(new QVBoxLayout()); 
    frame2->layout()->addWidget(new QLineEdit()); 
    frame2->layout()->addWidget(new QLineEdit()); 
    frame2->layout()->addWidget(new QLineEdit()); 
    frame2->hookChildrenWidgetsFocus(); 

    QHBoxLayout *centralLayout = new QHBoxLayout(); 
    centralLayout->addWidget(frame1); 
    centralLayout->addWidget(frame2); 

    QWidget *centralWidget = new QWidget(); 
    centralWidget->setLayout(centralLayout); 

    setCentralWidget(centralWidget); 
} 
+0

阿奇,谢谢你的回复。你能给我一个关于如何为此目的扩展QFrame的指针吗? – Elwood

+0

完美。我特别喜欢'hookChildrenWidgetsFocus()'的想法。 (但是我有一点点良心,因为我从Fred取走了接受人,他早先提出了一个类似的方法,非常感谢你们两个!) – Elwood

2

首先,创建的QFrame一个简单的子类,重新实现了eventFilter(QObject*, QEvent*)虚函数:

class MyFrame : public QFrame { 
    Q_OBJECT 

public: 
    MyFrame(QWidget *parent = 0, Qt::WindowFlags f = 0); 
    ~MyFrame(); 

    virtual bool eventFilter(QObject *watched, QEvent *event); 
}; 

使用MyFrame而不是QFrame含有小部件。然后,在某处你的代码中创建包含在MyFrame小部件,这些部件安装一个事件过滤器:

// ... 
    m_myFrame = new MyFrame(parentWidget); 
    QVBoxLayout *layout = new QVBoxLayout(myFrame); 
    m_button = new QPushButton("Widget 1", myFrame); 

    layout->addWidget(m_button); 
    m_button->installEventFilter(myFrame); 
    //... 

在这一点上,MyFrame::eventFilter()将被称为之前的任何事件发送到窗口小部件,让您在小部件意识到之前就采取行动。在MyFrame::eventFilter()之内,如果要过滤出事件(即,您不希望小部件处理事件),则返回true,否则返回false

bool MyFrame::eventFilter(QObject *watched, QEvent *event) 
{ 
    if (watched == m_button) { // An event occured on m_button 
     switch (event -> type()) { 
      case QEvent::FocusIn: 
       // Change the stylesheet of the frame 
       break; 
      case QEvent::FocusOut: 
       // Change the stylesheet back 
       break; 
      default: 
       break; 
     } 
    } 

    return false; // We always want the event to propagate, so always return false 
} 
+0

这就是我一直在寻找的,非常感谢,Fred! 'eventFilter()'中的if(watched == m_button)'是否有原因?它工作正常,没有和我可以添加尽可能多的小部件,而不必关心...... – Elwood

+0

在你的特定情况下,你不需要它,但'MyFrame'可能想要看几个不同的事件的小部件,所以简单检查'看着''让你知道哪个部件接收到一个事件(例如,你想使用不同的背景颜色,取决于哪个部件有焦点) – Fred

+0

Argh,为什么我不能接受两个答案?你和阿奇正在同一时间帮助我,你们都想出了类似的解决方案。我很抱歉,我终于接受了Archie的答案,因为他的解决方案稍微“完整”了一点。但是你的解释更好。我希望你能原谅我...;) – Elwood

相关问题