在 QTextEdit 中向任一方向扩展选择

Posted

技术标签:

【中文标题】在 QTextEdit 中向任一方向扩展选择【英文标题】:Extending selection in either direction in a QTextEdit 【发布时间】:2017-10-23 08:38:23 【问题描述】:

目前,QTextEdit 允许选择文本,然后仅在与锚点相对的选择侧使用 shift-click-drag 来更改该选择。锚点放置在选择开始的位置。如果用户试图在开始附近更改选择,则选择围绕锚点旋转而不是延伸。我想允许从任一侧更改选择。

我的第一次尝试是简单地将锚点设置在光标所在位置的另一侧。例如,选择是从 10 到 20。如果光标在位置 8 处被 shift-click-drag 拖动,则锚点将设置为 20。如果在位置 22 上 shift-click-drag 光标,则anchor 将设置为 10。稍后,我将尝试更健壮的方法,可能基于选择的中心点。

我认为这段代码会起作用,但它似乎根本不会影响默认行为。我错过了什么?

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class TextEditor(QTextEdit):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setReadOnly(True)
        self.setMouseTracking(True)

    def mouseMoveEvent(self, event):
        point = QPoint()
        x = event.x()    #these are relative to the upper left corner of the text edit window
        y = event.y()
        point.setX(x)
        point.setY(y)
        self.mousepos = self.cursorForPosition(point).position()  # get character position of current mouse using local window coordinates

        if event.buttons()==Qt.LeftButton:
            modifiers = QApplication.keyboardModifiers()
            if modifiers == Qt.ShiftModifier:
                start = -1 #initialize to something impossible
                end = -1
                cursor = self.textCursor()
                select_point1 = cursor.selectionStart()
                select_point2 = cursor.selectionEnd()
                if select_point1 < select_point2: # determine order of selection points
                    start = select_point1
                    end = select_point2
                elif select_point2 < select_point1:
                    start = select_point2
                    end = select_point1
                if self.mousepos > end: # if past end when shift-click then trying to extend right
                    cursor.setPosition(start, mode=QTextCursor.MoveAnchor)
                elif self.mousepos < start: # if before start when shift-click then trying to extend left
                    cursor.setPosition(end, mode=QTextCursor.MoveAnchor)
                if start != -1 and end != -1: #if selection exists then this should trigger
                    self.setTextCursor(cursor)

        super().mouseMoveEvent(event)

【问题讨论】:

【参考方案1】:

这是实现当前选择的 shift+click 扩展的第一个尝试。好像还可以,不过我还没试死,所以可能会有一两个小故障。预期的行为是在选择上方或下方的 shift+click 应该在该方向上扩展整个选择;并且带有拖动的 shift+click 应该做同样的事情,只是连续的。

请注意,我还设置了文本交互标志,以便插入符号在只读模式下可见,并且还可以使用键盘以各种方式操作选择(例如 ctrl+shift+right 将选择扩展到下一个词)。

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class TextEditor(QTextEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setReadOnly(True)
        self.setTextInteractionFlags(
            Qt.TextSelectableByMouse |
            Qt.TextSelectableByKeyboard)

    def mouseMoveEvent(self, event):
        if not self.setShiftSelection(event, True):
            super().mouseMoveEvent(event)

    def mousePressEvent(self, event):
        if not self.setShiftSelection(event):
            super().mousePressEvent(event)

    def setShiftSelection(self, event, moving=False):
        if (event.buttons() == Qt.LeftButton and
            QApplication.keyboardModifiers() == Qt.ShiftModifier):
            cursor = self.textCursor()
            start = cursor.selectionStart()
            end = cursor.selectionEnd()
            if not moving or start != end:
                anchor = cursor.anchor()
                pos = self.cursorForPosition(event.pos()).position()
                if pos <= start:
                    start = pos
                elif pos >= end:
                    end = pos
                elif anchor == start:
                    end = pos
                else:
                    start = pos
                if pos <= anchor:
                    start, end = end, start
                cursor.setPosition(start, QTextCursor.MoveAnchor)
                cursor.setPosition(end, QTextCursor.KeepAnchor)
                self.setTextCursor(cursor)
                return True
        return False

if __name__ == '__main__':

    app = QApplication(sys.argv)
    window = TextEditor()
    window.setText(open(__file__).read())
    window.setGeometry(600, 50, 800, 800)
    window.show()
    sys.exit(app.exec_())

【讨论】:

再一次,您的代码完美运行——我不完全理解如何。 if pos &lt;= anchor: start, end = end, start 切换变量,所以start 总是小于end(使用我只在 Python 中见过的语法)。但是,我真的希望您必须将锚点直接移动或设置到正在修改的选择的另一侧。 @davideps。如果pos 高于(小于)当前锚点,插入符号应该在选择的顶部结束。这正是用鼠标向上 拖动选择时会发生的情况。因此,对于这种情况,必须从endstart 进行选择,并且必须交换值。我已经稍微修改了我的示例,以便在 cursor.setPosition 调用中更加明确。

以上是关于在 QTextEdit 中向任一方向扩展选择的主要内容,如果未能解决你的问题,请参考以下文章

在pygame中向鼠标方向射击子弹

在as3中向不同方向拍摄

在 QTextEdit 窗口中选择文本并使用 setTextBackgroundColor 突出显示

如何失去 QTextEdit 的选择焦点?

将 qDebug 重定向到发出的信号

QTextEdit focusOut 以编程方式不起作用