例如,我尝试创建的一个小部件是QToolButton
和QLineEdit
的混合。
当leaveEvent()
出现时,它显示为QToolButton
,左侧带有图标/文字&右侧的{-1}}菜单箭头。当(QToolButton.MenuButtonPopup
出现时,按钮的左半部分(图标/文字)变为enterEvent()
,而右半部分仍然是下拉菜单。
我一直在浏览谷歌搜索带来的任何论坛,虽然我松散地了解如何绘制它,我如何正确地连接事件?如果我绘制QLineEdit
,我该如何让自定义窗口小部件的那部分行动并像QLineEdit
一样回复? (Python首选,C ++没问题)
[QLineEdit
将无效,而且我想创建的其他小部件肯定没有任何近似的等效内容。此外,我知道我可以用其他更简单的小部件构建一个小部件,然后弄乱样式表来实现类似的外观,但我知道上面有一个答案,因为Qt做到了,它会有更好的交叉 - 系统样式然后编写自定义样式表。]
答案 0 :(得分:1)
理解这个问题的关键是认识到没有实际的小部件存在就没有行为。因此,仅仅使用样式机制来绘制给定的控件是不够的。您需要QWidget
的实例(例如,QToolButton
或QLineEdit
)。一旦你拥有了它,你也可以像孩子一样拥有它,让Qt的事件传播处理适当的事件。这会引起很多麻烦。
如果您希望工具按钮的行为具有嵌入式行编辑,则最简单的方法是将行编辑实际作为工具按钮的子窗口小部件。您从QToolButton
继承,并根据需要显示/隐藏行编辑子项。此继承还允许您利用控件窗口小部件中存在的密钥保护方法:initStyleOption
。使用组合(has-a)而不是继承(is-a),你需要一个仅将QToolButton::initStyleOption
方法公开给朋友类的适配器类。
从焦点角度来看,您的预期行为很成问题。只使用键盘时,该按钮应可编辑和。仅仅使用鼠标进入/离开事件来暴露行编辑器 。合理的方法可能是按 Enter 或返回进入编辑模式 - 是的,这是两个不同的键!
您还需要了解Qt的可访问性如何工作,并确保您的窗口小部件的行为正常 - 我根本没有解决过这个问题。总而言之,设计控件(而不仅仅是可视化小部件)并不是一项简单的任务,如果您真的需要“调整”标准控件而不是通过样式设置,您总是需要三思而后行。
下面的代码演示了一个相当小的实现,它仍然在焦点方面表现得相当合理。我没有在OS X 10.9上测试它,除了Qt 4.8.5和5.2,所以YMMV,但我希望它能适用于任何合理的平台风格。
最后的挑剔:我不太明白你的意思是“QComboBox无效”。您的实现本质上是一个混淆的组合框,与典型的HIG(人机界面指南)不兼容。你基本上是在制作一个基于工具按钮的组合框混蛋孩子,看起来很奇怪。它不是一个组合框,菜单与按钮的内容完全分开。有什么意义?
#include <QApplication>
#include <QToolButton>
#include <QLineEdit>
#include <QGridLayout>
#include <QStyle>
#include <QStyleOptionButton>
#include <QMenu>
#include <QPushButton>
#include <QKeyEvent>
#include <QDebug>
class EditButton : public QToolButton {
Q_OBJECT
QLineEdit * m_edit;
QRect m_textGeometry;
Q_PROPERTY(QString text READ text WRITE setText NOTIFY newText USER true)
public:
EditButton(QWidget * parent = 0) : QToolButton(parent),
m_edit(new QLineEdit(this))
{
m_edit->hide();
connect(m_edit, SIGNAL(textChanged(QString)), SIGNAL(newText(QString)));
connect(m_edit, SIGNAL(editingFinished()), SLOT(hideEditor()));
setFocusPolicy(Qt::StrongFocus);
}
QString text() const { return m_edit->text(); }
void setText(const QString & text) {
if (text == m_edit->text()) return;
m_edit->setText(text);
QToolButton::setText(text);
emit newText(text);
}
Q_SIGNAL void newText(const QString &);
protected:
void resizeEvent(QResizeEvent * ev) {
QToolButton::resizeEvent(ev);
setEditGeometry();
}
void keyPressEvent(QKeyEvent * ev) {
if (ev->key() == Qt::Key_Enter || ev->key() == Qt::Key_Return) {
showEditor();
return;
}
QToolButton::keyPressEvent(ev);
}
void enterEvent(QEvent * ev) {
showEditor();
QToolButton::enterEvent(ev);
}
void leaveEvent(QEvent * ev) {
hideEditor();
QToolButton::leaveEvent(ev);
}
private:
Q_SLOT void hideEditor() {
QToolButton::setText(m_edit->text());
setFocusProxy(0);
m_edit->hide();
update();
}
void showEditor() {
setEditGeometry();
m_edit->show();
setFocusProxy(m_edit);
setFocus();
}
void setEditGeometry() {
QStyleOptionToolButton opt;
initStyleOption(&opt);
QRect r = style()->subControlRect(QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton, this);
m_edit->setGeometry(r);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QGridLayout * l = new QGridLayout(&window);
EditButton * btn = new EditButton;
btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QMenu * menu = new QMenu(btn);
menu->addAction("Action!");
btn->setMenu(menu);
btn->setPopupMode(QToolButton::MenuButtonPopup);
btn->setText("Foo Bar Baz");
l->addWidget(btn);
l->addWidget(new QPushButton("Focus Test Button"));
window.show();
return a.exec();
}
#include "main.moc"