How to implement the “Edit” menu with “Undo”, “Cut”, “Paste” and “Copy”?

后端 未结 4 462
野的像风
野的像风 2021-01-12 06:34

Greetings,

for one of my applications I\'m trying to implement an \"Edit\" menu. This menu usually has the standard-entries Undo, Cut, Copy

相关标签:
4条回答
  • 2021-01-12 07:04

    My impression is that the Edit menu applies to the central document widget, not loads of small ones. I have not tested, but if you have a form with QLineEdits, does the Edit menu (in the menu bar) really apply to that widget. Don't you simple bring up the context menu or press the short-cuts to access these options...

    0 讨论(0)
  • 2021-01-12 07:06

    user285740's solution didn't help me, since I'm using a browser control in my app (CEF or WebKit, doesn't matter).

    Why? For browsers, focusWidget() always seems to be NULL, since <input> elements are not widgets. I tried postEvent() to other widgets - didn't work. Adding menu items with QAction::TextHeuristicRole + standard sequences like QKeySequence::Copy didn't do the job, too (I could connect them only to my slots, not to standard slots). Cefclient sample loads a xib file, but it's not an option for me, since Qt creates everything from scratch.

    Eventually, I found the solution! Create the same menu items from ObjectiveC++ code. They act like the ones created via QMenuBar, but (!) they can be connected to some real automatic actions like @selector(copy:)

    You can find an example here: nsMenuUtilsX::GetStandardEditMenuItem(), just do that from your ObjC++ code.

    But, this code doesn't work if you execute it before QApplication::exec(). Qt then "rewrites" the main menu programmatically... How to fix that? Well, maybe I'll add some hack like a QTimer. It doesn't do that if you don't try to add another items via QMenuBar. It's OK now! Qt-independent menu.

    0 讨论(0)
  • 2021-01-12 07:13

    It's easy enough to accomplish half of the necessary functionality. Just create the Edit menu, along with the necessary QActions (copy/paste/undo/etc.) in your main window class and connect them to slots. In the slots, emulate the correct key press and release events (e.g. Ctrl+C for Copy) and send them to the currently focused widget. In code, something like this:

    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 ));
    }
    

    Of course, this is quite a hack. You need to modify the code for each target platform, changing the keyboard shortcuts to the correct ones, and it might happen that a widget that receives focus does something quiet unexpected with Ctrl+C. The worst downside in this method, in my opinion, is that you cannot properly control the enabled state of the Edit menu items. It is not possible to query from a generic widget whether a copy or paste operation would be possible or not.

    I am unable to find a real solution to this problem - and would be surprised to find out that one exists - as the copy/paste functionality is generally hidden inside the class' code and not exposed through any standard set of signals/slots. After tonight's experiments with the functionality, I have decided to just forget having an Edit menu from my application and expect the users to know the keyboard shortcuts, or use the context sensitive menus.

    0 讨论(0)
  • 2021-01-12 07:16

    The best solution I could find for this comes from https://www.qtcentre.org/threads/10709-using-cut()-copy()-paste(). In my app, this ended up looking like this:

    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();
    });
    

    This is really awful, and has to be done for each of the standard menu items (undo, redo, cut, copy, paste, delete, select all...), and getting the menu items to enable/disable correctly requires yet more hoops to be jumped through. This is the first time, in porting a Cocoa app to Qt, that I have felt that Qt is clearly and markedly inferior (in this case, to Cocoa's first responder mechanism, which doesn't seem to exist in Qt at all). Still, I think it's better than the solution proposed by user285740, which hard-codes particular keyboard actions. YMMV.

    0 讨论(0)
提交回复
热议问题