Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt5 QLabel::setTextInteractionFlags() not behaving as expected



  • I am using Qt 5.7. I have inherited code reading:

    label = QLabel("Word1 Word2", self)
    label.setTextInteractionFlags(Qt.TextSelectableByMouse)
    

    Docs for Qt.TextSelectableByMouse (http://doc.qt.io/qt-5/qt.html#TextInteractionFlag-enum):

    Qt::TextSelectableByMouse 1 Text can be selected with the mouse and copied to the clipboard using a context menu or standard keyboard shortcuts.

    This creates a label. I can use the mouse to select all or part of the text. So far so good.

    I am reliably informed by stakeholder that at Qt 4 with this code, after selecting some text (in their case Word2, I don't think that's relevant, but must work in any proposed solution) user could click Ctrl+C and text would be copied to clipboard correctly. This corresponds to the documentation above "copied to the clipboard using [...] standard keyboard shortcuts."

    No copying to clipboard happens under Qt 5.7.

    I note that I can right-click and a context menu pops up. There I see Copy shown (which works if I click on it), and also Select All Ctrl+A. Ctrl+A does work to select all text. Ctrl+C does not work.

    • Under Linux the Copy is written with an underline under the C. Implying Ctrl+C should work.
    • Under Windows I am told the Copy does not have its C underlined.

    Anyway, the gist is: stakeholder needs functionality as it (apparently) was under Qt 4: Ctrl+C should copy selected text. What is going on with the documentation/behaviour wrt the supposed but non-functioning support for "standard keyboard shortcuts"?



  • Solved! The reason the label did not get the Ctrl+C for copy is that the (unrelated) QTableView on the page has a Copy shortcut and that (only) is receiving the shortcut.

    I have to say this was not clear to me from the documentation, but a QAction has a http://doc.qt.io/qt-5/qaction.html#shortcutContext-prop, and the default from http://doc.qt.io/qt-5/qt.html#ShortcutContext-enum is Qt::WindowShortcut, meaning that it applies to the whole window. If you define a QAction for a widget you need to call:

    self.copyAction.setShortcutContext(Qt.WidgetShortcut)
    

    to restrict it to the widget only. Once I did this, the Ctrl+C was free to work independently on my QLabel to allow copying there.

    @mrjj Thanks for your input. The above is what I needed to learn.


  • Lifetime Qt Champion

    Hi
    Just tested.
    Works in 5.11.1 on windows. ctrl+c does copy labels text to clipboard.



  • @mrjj
    Thanks @mrjj, I thought you'd be a good one for this question! :)

    Now that I know it is at least supposed to work, I think I'll first set up a standalone test with 5.7 to make sure it's not some artefact of the big project, and then put it down as a "will work when Qt next updated"!


  • Lifetime Qt Champion

    @JonB
    hi
    Well one liners are a delight to test :)
    You need a reverse test. i install 5.7 and see if it stops working ?



  • @mrjj
    Houston, we have a problem....

    I tried in a standalone. Sure enough it does work (Linux). Sigh....

    One notable difference: in the standalone which works, the right-click context menu does have the shortcut Ctrl+C shown (at the right-hand side) against Copy. Just like the Ctrl+A shown against Select All which has always worked. But (hence I wrote it above as a clue) in the actual project the menu's Copy does not show Ctrl+C. Clearly at some level this is the issue, so...

    ...What would make the context menu not show that??


  • Lifetime Qt Champion

    @JonB
    Oh that is odd.
    As far as i know menu comes from createStandardContextMenu()
    but maybe label uses another one
    Browsing
    https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qlabel.cpp.html#_ZN6QLabel23setTextInteractionFlagsE6QFlagsIN2Qt19TextInteractionFlagEE
    to see if we can find what makes the menu for us.

    update:
    this one does it
    https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qwidgettextcontrol.cpp.html#_ZN18QWidgetTextControl25createStandardContextMenuERK7QPointFP7QWidget

    update2:

    must be something in this that is different from test to real app

    #define ACCEL_KEY(k) ((!QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) \
                           && QGuiApplication::styleHints()->showShortcutsInContextMenus()) \
                          && !qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \
                          QLatin1Char('\t') + QKeySequence(k).toString(QKeySequence::NativeText) : QString())
    
    

    I do wonder if something else register this shortcutkey that
    hasShortcutForKeySequence fails and hence its not added.

    i would try call
    qApp->d_func()->shortcutMap.hasShortcutForKeySequence(QKeySequence::Copy)
    and see if it returns true for the real app. ( if possible. seems to be inside private class)



  • @mrjj
    Can't get as far as d_func (PyQt, and no sources).

    We know that other shortcuts (e.g. Ctrl+A) are shown on menu, so it's not global. No occurrences of QKeySequence::Copy Damn, but there is an obscure one, and 'coz it's Python that's QKeySequence.Copy, which I failed to check :(.

    Found it works on one page in my project, not on the one I want. Clearly I have goodness-knows-what to search the code for to track this down.... :(



  • @mrjj
    OK, mystery both "solved" & "deepened"!

    Elsewhere on the page causing me problems, I have a QTableView for which "selected row copy" is enabled. Code for that widget is like:

    class JTableView(QtWidgets.QTableView):
        """Table view with copy enabled"""
        def __init__(self, parent=None):
            super().__init__(parent)
    
            # Allow Ctrl+C to copy the table to the clipboard
            self.copyAction = QAction("Copy", self)
            self.copyAction.setShortcut(QKeySequence.Copy)
            self.copyAction.triggered.connect(self.copyToClipboard)
            self.addAction(self.copyAction)
    

    If I hack out the copyAction lines temporarily, the copying of the label text springs back to life.

    Note that the self here is the QTableView itself, so why is that code affecting the whole page?

    Now, there is a difference here from what used to be there and worked at Qt 4. In the old code the Ctrl+C on a table was recognised by actual key-press event code. I asked about this in this forum in topic https://forum.qt.io/topic/92513/correctly-detecting-ctrl-key-click. In a reply there @SGaist suggested it would be better to change key-event code over to a shortcut action, which is what I did above. That must be why it worked previously but not now. Why??!!


  • Lifetime Qt Champion

    Hi
    I wonder if label do get keyboard focus when selected text.
    Else it might be the table that fas focus and hence get the shortcut activation.



  • Solved! The reason the label did not get the Ctrl+C for copy is that the (unrelated) QTableView on the page has a Copy shortcut and that (only) is receiving the shortcut.

    I have to say this was not clear to me from the documentation, but a QAction has a http://doc.qt.io/qt-5/qaction.html#shortcutContext-prop, and the default from http://doc.qt.io/qt-5/qt.html#ShortcutContext-enum is Qt::WindowShortcut, meaning that it applies to the whole window. If you define a QAction for a widget you need to call:

    self.copyAction.setShortcutContext(Qt.WidgetShortcut)
    

    to restrict it to the widget only. Once I did this, the Ctrl+C was free to work independently on my QLabel to allow copying there.

    @mrjj Thanks for your input. The above is what I needed to learn.


  • Lifetime Qt Champion

    Ah cool. never noticed the Qt::WindowShortcut default :)
    Good found. Now we know next time what to check for when shortcuts stops working.


Log in to reply