如何实现带有“撤销”、“剪切”、“粘贴”和“复制”的“编辑”菜单?

10

问候,

我正在尝试实现一个“编辑”菜单用于我的应用程序。这个菜单通常有标准条目:撤销剪切复制粘贴

默认情况下,这个菜单并不在那里,但用户似乎特别期望它在Mac OS X上出现。

是否有更容易的方法来实现这个菜单,而不需要在每个部件中手动完成?由于大多数部件已经通过快捷键实现了复制/粘贴/撤消机制,我想提供一些简单的菜单操作,调用它们。

这些操作应该首先调用具有焦点的部件,然后将事件向上传递到对象链中,我猜。

我正在使用Qt 4.6在Windows、Linux和Mac OS X上。

谢谢!

4个回答

7

完成一半的必要功能非常容易。只需在主窗口类中创建编辑菜单,并添加必要的QActions(复制/粘贴/撤消/等),然后将它们连接到相应的槽函数。在槽函数中,模拟正确的按键按下和释放事件(例如,Ctrl+C为复制),并将它们发送给当前聚焦的小部件。代码示例如下:

MainWindow::MainWindow(...)
{
    ...
    connect( actionCopy, SIGNAL( triggered()), SLOT( copy()));
    ...
}
...
void MainWindow::copy()
{
    QWidget* focused = QApplication::focusWidget();
    if( focused != 0 )
    {
        QApplication::postEvent( focused,
                                 new QKeyEvent( QEvent::KeyPress,
                                                Qt::Key_C,
                                                Qt::ControlModifier ));
        QApplication::postEvent( focused,
                                 new QKeyEvent( QEvent::KeyRelease,
                                                Qt::Key_C,
                                                Qt::ControlModifier ));
}

当然,这是一种相当的hack。您需要修改每个目标平台的代码,将键盘快捷键更改为正确的快捷键,并且可能会发生接收焦点的小部件使用Ctrl+C执行意外操作的情况。在我看来,这种方法最糟糕的缺点是您无法正确控制编辑菜单项的启用状态。通常情况下,无法从通用小部件查询是否可能进行复制或粘贴操作。
我无法找到解决此问题的真正解决方案 - 如果存在一个解决方案,我会感到惊讶 - 因为复制/粘贴功能通常隐藏在类的代码中,并未通过任何标准的信号/插槽集公开。在今晚对功能的实验之后,我已经决定放弃在我的应用程序中拥有编辑菜单,并期望用户知道键盘快捷键或使用上下文敏感菜单。

0

user285740的方案对我没有帮助,因为我在我的应用程序中使用了浏览器控件(CEF或WebKit都行)。

为什么? 对于浏览器而言,focusWidget() 看起来总是 NULL ,因为 <input> 元素不是小部件。 我尝试将 postEvent()发送到其他小部件 - 没有效果。 使用 QAction :: TextHeuristicRole 和诸如QKeySequence :: Copy之类的标准序列添加菜单项也无法解决问题(我只能将它们连接到我的插槽,而不能连接到标准插槽)。 cefclient示例加载一个xib文件,但对我来说不是一个选项,因为Qt从头开始创建所有内容。

最终,我找到了解决方案!通过ObjectiveC ++代码创建相同的菜单项。 它们的作用就像通过QMenuBar创建的菜单项,但是它们可以连接到一些真正的自动操作,例如@selector(copy:)

你可以在这里找到一个例子:nsMenuUtilsX::GetStandardEditMenuItem(),只需从你的ObjC++代码中执行它。

但是,如果在QApplication::exec()之前执行此代码,则不起作用。Qt会以编程方式“重写”主菜单... 如何解决?嗯,也许我会添加一些像QTimer这样的黑客。 如果您不尝试通过QMenuBar添加其他项,则不会这样做。现在没问题了!独立于Qt的菜单。


0

我的印象是编辑菜单适用于中央文档小部件,而不是许多小部件。我没有测试过,但如果您有一个带有QLineEdits的表单,编辑菜单(在菜单栏中)是否真的适用于该小部件。难道您不只是弹出上下文菜单或按快捷键来访问这些选项吗...


2
这可能对于类似Windows/Linux的窗口管理器是正确的。然而,在OS X上,您在屏幕顶部有一个应用程序范围的菜单栏,而不是每个窗口的顶部。Mac用户期望所选的菜单操作对最上面的窗口和当前具有焦点的小部件产生影响。(选择粘贴将把剪贴板中的任何内容粘贴到当前具有焦点的QLineEdit中,等等)。 - BastiBen

0

我找到的最佳解决方案来自https://www.qtcentre.org/threads/10709-using-cut()-copy()-paste()。在我的应用程序中,它最终看起来像这样:

connect(ui->actionCut, &QAction::triggered, []() {
    QWidget *focusWidget = QApplication::focusWidget();
    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);
    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);

    if (lineEdit && lineEdit->isEnabled() && !lineEdit->isReadOnly())
        lineEdit->cut();
    else if (textEdit && textEdit->isEnabled() && !textEdit->isReadOnly())
        textEdit->cut();
});

这真的很糟糕,每个标准菜单项(撤销、重做、剪切、复制、粘贴、删除、全选等)都必须这样做,使菜单项正确启用/禁用需要更多的跳跃。这是在将Cocoa应用程序移植到Qt时,我第一次感到Qt明显不如(在这种情况下,与Cocoa的第一响应机制相比,在Qt中似乎根本不存在)。尽管如此,我认为它比用户285740提出的解决方案要好,后者硬编码了特定的键盘操作。你的经验可能会有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接