Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to override Paste or catch the moment before Paste happens in QLineEdit?
Forum Updated to NodeBB v4.3 + New Features

How to override Paste or catch the moment before Paste happens in QLineEdit?

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 4 Posters 2.4k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    Rian Firth
    wrote on last edited by Rian Firth
    #1

    I need to change the behavior of "Paste" (completely override, make it act in a different way) in the standard context menu of the QLineEdit.
    Or at least somehow catch the moment before Paste is about to happen in QLineEdit and do some preparations (clean the text line).
    How can I do it for both the context menu and shortcut ctr+v?

    I have something like this:

    MyLineEdit::MyLineEdit(QWidget* parent)
    	: QLineEdit(parent)
    {
    	setContextMenuPolicy(Qt::CustomContextMenu);
    	connect(this, &MyLineEdit::customContextMenuRequested, this, &MyLineEdit::ShowContextMenu);
    }
    
    void MyLineEdit::ShowContextMenu(const QPoint& pos)
    {
    	QScopedPointer<QMenu> menu(createStandardContextMenu());
    	QAction* defaultPaste = menu->actions()[5];
    
    	// How can I override default Paste functionality here?
    	// Or at least add some functionality before QLineEdit::paste() slot will be executed?
    
    	menu->exec(mapToGlobal(pos));
    }
    

    It's not necessary to use this code/this way tho. Any better/proper way is appreciated.

    Pl45m4P 1 Reply Last reply
    1
    • R Rian Firth

      I need to change the behavior of "Paste" (completely override, make it act in a different way) in the standard context menu of the QLineEdit.
      Or at least somehow catch the moment before Paste is about to happen in QLineEdit and do some preparations (clean the text line).
      How can I do it for both the context menu and shortcut ctr+v?

      I have something like this:

      MyLineEdit::MyLineEdit(QWidget* parent)
      	: QLineEdit(parent)
      {
      	setContextMenuPolicy(Qt::CustomContextMenu);
      	connect(this, &MyLineEdit::customContextMenuRequested, this, &MyLineEdit::ShowContextMenu);
      }
      
      void MyLineEdit::ShowContextMenu(const QPoint& pos)
      {
      	QScopedPointer<QMenu> menu(createStandardContextMenu());
      	QAction* defaultPaste = menu->actions()[5];
      
      	// How can I override default Paste functionality here?
      	// Or at least add some functionality before QLineEdit::paste() slot will be executed?
      
      	menu->exec(mapToGlobal(pos));
      }
      

      It's not necessary to use this code/this way tho. Any better/proper way is appreciated.

      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote on last edited by Pl45m4
      #2

      @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

      catch the moment before Paste is about to happen in QLineEdit and do some preparations

      The problem is that it is not done within QLineEdit class.

      See here
      The QLineEdit::paste() just triggers the internal paste function (here), which takes the content from clipboard and inserts it to your widget. And because it's internal, you cant just access or intercept it without changing the Qt source.

      You could try to grab the keyEvent and check if the pressed key(-sequence) is QKeySequence::Paste (https://doc.qt.io/qt-5/qkeysequence.html#standard-shortcuts) and then do your stuff.


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      R 1 Reply Last reply
      1
      • R Offline
        R Offline
        Rian Firth
        wrote on last edited by Rian Firth
        #3

        Isn't there a way to do something with QLineEdit::paste() slot?

        You could try to grab the keyEvent and check if the pressed key(-sequence) is QKeySequence::Paste (https://doc.qt.io/qt-5/qkeysequence.html#standard-shortcuts) and then do your stuff.

        But what about context menu Paste action?
        It'll change shortcut behavior but if you'll click Paste in the context menu it'll be still the same.

        Pl45m4P 1 Reply Last reply
        0
        • R Rian Firth

          Isn't there a way to do something with QLineEdit::paste() slot?

          You could try to grab the keyEvent and check if the pressed key(-sequence) is QKeySequence::Paste (https://doc.qt.io/qt-5/qkeysequence.html#standard-shortcuts) and then do your stuff.

          But what about context menu Paste action?
          It'll change shortcut behavior but if you'll click Paste in the context menu it'll be still the same.

          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by Pl45m4
          #4

          @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

          It'll change shortcut behavior but if you'll click Paste in the context menu it'll be still the same.

          You have access to your context menu and its QActions, dont you?!

          There you can add a connection to do your custom stuff before you call the QLineEdit::paste() slot.

          Maybe you have to disconnect everything from your standard Paste-QAction first, because I don't know if the connection is made, when creating the "standard context menu". Then the paste would happen before you can do your stuff. So delete the default connection, connect to your slot and then call paste() when you are ready to insert the text.

          -> defaultPaste->disconnect() // Disconnects all slots from object

          @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

          menu->actions()[5]

          Make sure that 5 is always the paste action. The order might change, esp. when you add more QActions to your menu.


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          1 Reply Last reply
          2
          • R Offline
            R Offline
            Rian Firth
            wrote on last edited by Rian Firth
            #5

            So delete the default connection, connect to your slot and then call paste() when you are ready to insert the text.

            Oh, this does the trick!
            So I do this for the context menu and I also should do what you said earlier about keyEvent to override whole paste functionality?
            You either ctrl+v or click Paste in the context menu, there's nothing else I should be worried about?
            There's no other way to paste text in QLineEdit?

            Make sure that 5 is always the paste action. The order might change, esp. when you add more QActions to your menu.

            I'd really like to use findChild<QAction*>("action_name") but objectName's are not set for created actions: https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qlineedit.cpp.html#2210

            Pl45m4P 1 Reply Last reply
            0
            • R Rian Firth

              So delete the default connection, connect to your slot and then call paste() when you are ready to insert the text.

              Oh, this does the trick!
              So I do this for the context menu and I also should do what you said earlier about keyEvent to override whole paste functionality?
              You either ctrl+v or click Paste in the context menu, there's nothing else I should be worried about?
              There's no other way to paste text in QLineEdit?

              Make sure that 5 is always the paste action. The order might change, esp. when you add more QActions to your menu.

              I'd really like to use findChild<QAction*>("action_name") but objectName's are not set for created actions: https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qlineedit.cpp.html#2210

              Pl45m4P Offline
              Pl45m4P Offline
              Pl45m4
              wrote on last edited by Pl45m4
              #6

              @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

              You either ctrl+v or click Paste in the context menu, there's nothing else I should be worried about?

              How else you want to paste from clipboard? I only know about keyboard shortcuts (Ctrl + V or Insert key) and menus.

              @Pl45m4 said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

              because I don't know if the connection is made, when creating the "standard context menu"

              I can confirm that now :)
              (createStandardContextMenu() Code)

              @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

              I'd really like to use findChild<QAction*>("action_name") but objectName's are not set for created actions:

              I guess you can work with the shortcut... (unless you don't change it manually!)

              action->shortcut() returns a QKeySequence. And you know it has to be QKeySequence::Paste You only need to check which the primary KeySequence is (what shortcut()returns... Ctrl + V or "Paste" or whatever), since shortcut() returns the primary only.
              Otherwise you could use shortcuts(), but this will return a list with all shortcuts for this widget... so you would have to check and compare even more...

              • https://doc.qt.io/qt-5/qaction.html#shortcut

              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              1 Reply Last reply
              1
              • Pl45m4P Pl45m4

                @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

                catch the moment before Paste is about to happen in QLineEdit and do some preparations

                The problem is that it is not done within QLineEdit class.

                See here
                The QLineEdit::paste() just triggers the internal paste function (here), which takes the content from clipboard and inserts it to your widget. And because it's internal, you cant just access or intercept it without changing the Qt source.

                You could try to grab the keyEvent and check if the pressed key(-sequence) is QKeySequence::Paste (https://doc.qt.io/qt-5/qkeysequence.html#standard-shortcuts) and then do your stuff.

                R Offline
                R Offline
                Rian Firth
                wrote on last edited by Rian Firth
                #7

                @Pl45m4 said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

                You could try to grab the keyEvent and check if the pressed key(-sequence) is QKeySequence::Paste (https://doc.qt.io/qt-5/qkeysequence.html#standard-shortcuts) and then do your stuff.

                Did you mean something like this?
                It works but feels so wrong.

                MyLineEdit::MyLineEdit(QWidget * parent)
                	: QLineEdit(parent)
                {
                	setContextMenuPolicy(Qt::CustomContextMenu);
                	connect(this, &MyLineEdit::customContextMenuRequested, this, &MyLineEdit::ShowContextMenu);
                
                	QShortcut* shortcut = new QShortcut(QKeySequence::Paste, this); // It works only with these two lines.
                	qApp->installEventFilter(this);                                 // And I've no idea how it works.
                }
                
                void MyLineEdit::MyPaste()
                {
                	clear();
                	paste();
                }
                
                void MyLineEdit::ShowContextMenu(const QPoint& pos)
                {
                	QScopedPointer<QMenu> menu(createStandardContextMenu());
                	QAction* defaultPaste = menu->actions()[5];
                	defaultPaste->disconnect(); // Remove connect(action, SIGNAL(triggered()), SLOT(paste()));
                
                	// Because of QShortcut* shortcut = new QShortcut(QKeySequence::Paste, this); in constructor
                	// Paste doesn't have shortcut in the context menu, setting it to default one again
                	defaultPaste->setShortcut(QKeySequence::Paste);
                
                	connect(defaultPaste, &QAction::triggered, [this]() {
                		MyPaste(); // Override the context menu Paste's functionality
                	});
                
                	menu->exec(mapToGlobal(pos));
                }
                
                bool MyLineEdit::eventFilter(QObject *watched, QEvent *event)
                {
                	if (event->type() == QEvent::ShortcutOverride) {
                		QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
                
                		if (keyEvent->matches(QKeySequence::Paste))
                		{
                			MyPaste(); // Override Ctrl+V functionality
                			return true;
                		}
                	}
                
                	return QLineEdit::eventFilter(watched, event);
                }
                

                Especially these two lines:

                QShortcut* shortcut = new QShortcut(QKeySequence::Paste, this); // It works only with these two lines.
                qApp->installEventFilter(this);                                 // And I've no idea how it works.
                

                It doesn't want to work without creating a new QShortcut.

                Am I doing something wrong?

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  SimonSchroeder
                  wrote on last edited by
                  #8

                  @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

                  Am I doing something wrong?

                  You install the event filter on qApp. This is not a good idea. For all widgets this one MyLineEdit will intercept Ctrl+V. Just try having two line edits and you probably will see some weird behavior.

                  If you want to use eventFilter() (which is a reasonable choice), you should make a separate class (derived from QObject) just for event filtering and install it on a single QLineEdit, or rather MyLineEdit in your case. The reason for this is that the filter should only apply to this single widget and not everyone else.

                  There's no other way to paste text in QLineEdit?

                  I am not entirely sure. But I suspect that there is also some drag'n'drop behavior here. At least there should be dragging and dropping within the line edit itself. Furthermore, you might be able to drop text from anywhere else.

                  Pl45m4P 1 Reply Last reply
                  1
                  • S SimonSchroeder

                    @Rian-Firth said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

                    Am I doing something wrong?

                    You install the event filter on qApp. This is not a good idea. For all widgets this one MyLineEdit will intercept Ctrl+V. Just try having two line edits and you probably will see some weird behavior.

                    If you want to use eventFilter() (which is a reasonable choice), you should make a separate class (derived from QObject) just for event filtering and install it on a single QLineEdit, or rather MyLineEdit in your case. The reason for this is that the filter should only apply to this single widget and not everyone else.

                    There's no other way to paste text in QLineEdit?

                    I am not entirely sure. But I suspect that there is also some drag'n'drop behavior here. At least there should be dragging and dropping within the line edit itself. Furthermore, you might be able to drop text from anywhere else.

                    Pl45m4P Offline
                    Pl45m4P Offline
                    Pl45m4
                    wrote on last edited by
                    #9

                    @SimonSchroeder said in How to override Paste or catch the moment before Paste happens in QLineEdit?:

                    But I suspect that there is also some drag'n'drop behavior here

                    Ah yeah, forgot about that.


                    If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                    ~E. W. Dijkstra

                    1 Reply Last reply
                    0
                    • R Offline
                      R Offline
                      Rian Firth
                      wrote on last edited by Rian Firth
                      #10

                      This works and looks better than eventFilter.

                      MyLineEdit::MyLineEdit(QWidget * parent)
                      	: QLineEdit(parent)
                      {
                      	setContextMenuPolicy(Qt::CustomContextMenu);
                      	connect(this, &MyLineEdit::customContextMenuRequested, this, &MyLineEdit::ShowContextMenu);
                      }
                      
                      void MyLineEdit::MyPaste()
                      {
                      	clear();
                      	paste();
                      }
                      
                      void MyLineEdit::ShowContextMenu(const QPoint& pos)
                      {
                      	QScopedPointer<QMenu> menu(createStandardContextMenu());
                      	const auto actions = menu->actions();
                      	const QString translatedActionName = QCoreApplication::translate("QLineEdit", "&Paste");
                      	const auto it = std::find_if(actions.cbegin(), actions.cend(), [&translatedActionName](const QAction * action) {
                      		return action->text().startsWith(translatedActionName);
                      	});
                      
                      	if (it != actions.cend())
                      	{
                      		const auto actionPaste = *it;
                      		actionPaste->disconnect(SIGNAL(triggered()));
                      		connect(actionPaste, &QAction::triggered, this, &MyLineEdit::MyPaste); // Override the context menu's Paste functionality
                      	}
                      
                      	menu->exec(mapToGlobal(pos));
                      }
                      
                      void MyLineEdit::keyPressEvent(QKeyEvent *event)
                      {
                      	if (event->matches(QKeySequence::Paste))
                      	{
                      		MyPaste(); // Override Ctrl+V functionality
                      		event->accept();
                      		return;
                      	}
                      
                      	QLineEdit::keyPressEvent(event);
                      }
                      
                      1 Reply Last reply
                      1
                      • S Offline
                        S Offline
                        Sndr
                        wrote on last edited by Sndr
                        #11

                        I came across this post, which helped me in the right direction.

                        But instead of using the CustomContextMenu method, I would simply override the virtual contextMenuEvent (QContextMenuEvent *event) function.

                        Secondly, finding + disconnect the paste-action can be much easier and cleaner.

                        void MyLineEdit::MyPaste()
                        {
                            clear();
                            paste();
                        }
                        
                        void MyLineEdit::contextMenuEvent(QContextMenuEvent *event)
                        {
                            QMenu *menu = createStandardContextMenu();
                        
                            const QList<QAction*> actions = menu->actions();
                            foreach (QAction * action, actions)
                            {
                                // disconnect returns true if it successfully disconnected the slot "paste()".
                                // Thus disconnect fails for all non-"paste" actions :-)
                                if (action->disconnect(this, SLOT(paste())))
                                {
                                    connect(action, &QAction::triggered, this, &MyLineEdit::MyPaste); // Override the context menu's Paste functionality
                                    break;
                                }
                            }
                            menu->setAttribute(Qt::WA_DeleteOnClose);
                            menu->popup(event->globalPos());
                        }
                        
                        void MyLineEdit::keyPressEvent(QKeyEvent *event)
                        {
                            if (event->matches(QKeySequence::Paste))
                            {
                                MyPaste(); // Override Ctrl+V functionality
                                event->accept();
                                return;
                            }
                        
                            QLineEdit::keyPressEvent(event);
                        }
                        
                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved