【问题标题】:How to undo when using QScintilla setText?使用 QScintilla setText 时如何撤消?
【发布时间】:2019-07-03 14:12:07
【问题描述】:

让我先发布一些我将用来表达我的问题的小辅助函数:

import textwrap
import sys
from pathlib import Path

from PyQt5.Qsci import QsciScintilla
from PyQt5.Qt import *  # noqa


def set_style(sci):
    # Set default font
    sci.font = QFont()
    sci.font.setFamily('Consolas')
    sci.font.setFixedPitch(True)
    sci.font.setPointSize(8)
    sci.font.setBold(True)
    sci.setFont(sci.font)
    sci.setMarginsFont(sci.font)
    sci.setUtf8(True)

    # Set paper
    sci.setPaper(QColor(39, 40, 34))

    # Set margin defaults
    fontmetrics = QFontMetrics(sci.font)
    sci.setMarginsFont(sci.font)
    sci.setMarginWidth(0, fontmetrics.width("000") + 6)
    sci.setMarginLineNumbers(0, True)
    sci.setMarginsForegroundColor(QColor(128, 128, 128))
    sci.setMarginsBackgroundColor(QColor(39, 40, 34))
    sci.setMarginType(1, sci.SymbolMargin)
    sci.setMarginWidth(1, 12)

    # Set indentation defaults
    sci.setIndentationsUseTabs(False)
    sci.setIndentationWidth(4)
    sci.setBackspaceUnindents(True)
    sci.setIndentationGuides(True)
    sci.setFoldMarginColors(QColor(39, 40, 34), QColor(39, 40, 34))

    # Set caret defaults
    sci.setCaretForegroundColor(QColor(247, 247, 241))
    sci.setCaretWidth(2)

    # Set edge defaults
    sci.setEdgeColumn(80)
    sci.setEdgeColor(QColor(221, 221, 221))
    sci.setEdgeMode(sci.EdgeLine)

    # Set folding defaults (http://www.scintilla.org/ScintillaDoc.html#Folding)
    sci.setFolding(QsciScintilla.CircledFoldStyle)

    # Set wrapping
    sci.setWrapMode(sci.WrapNone)

    # Set selection color defaults
    sci.setSelectionBackgroundColor(QColor(61, 61, 52))
    sci.resetSelectionForegroundColor()

    # Set scrollwidth defaults
    sci.SendScintilla(QsciScintilla.SCI_SETSCROLLWIDTHTRACKING, 1)

    # Current line visible with special background color
    sci.setCaretLineBackgroundColor(QColor(255, 255, 224))

    # Set multiselection defaults
    sci.SendScintilla(QsciScintilla.SCI_SETMULTIPLESELECTION, True)
    sci.SendScintilla(QsciScintilla.SCI_SETMULTIPASTE, 1)
    sci.SendScintilla(QsciScintilla.SCI_SETADDITIONALSELECTIONTYPING, True)


def set_state1(sci):
    sci.clear_selections()
    base = "line{} state1"
    view.setText("\n".join([base.format(i) for i in range(10)]))
    for i in range(0, 10, 2):
        region = (len(base) * i, len(base) * (i + 1) - 1)
        if i == 0:
            view.set_selection(region)
        else:
            view.add_selection(region)


def set_state2(sci):
    base = "line{} state2"
    view.setText("\n".join([base.format(i) for i in range(10)]))
    for i in range(1, 10, 2):
        region = (len(base) * i, len(base) * (i + 1) - 1)
        if i == 1:
            view.set_selection(region)
        else:
            view.add_selection(region)


class Editor(QsciScintilla):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        set_style(self)

    def clear_selections(self):
        sci = self
        sci.SendScintilla(sci.SCI_CLEARSELECTIONS)

    def set_selection(self, r):
        sci = self
        sci.SendScintilla(sci.SCI_SETSELECTION, r[1], r[0])

    def add_selection(self, r):
        sci = self
        sci.SendScintilla(sci.SCI_ADDSELECTION, r[1], r[0])

    def sel(self):
        sci = self
        regions = []

        for i in range(sci.SendScintilla(sci.SCI_GETSELECTIONS)):
            regions.append(
                sci.SendScintilla(sci.SCI_GETSELECTIONNSTART, i),
                sci.SendScintilla(sci.SCI_GETSELECTIONNEND, i)
            )

        return sorted(regions)

其实我有几个问题:

问题 1)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    view = Editor()
    set_state1(view)
    view.move(1000, 100)
    view.resize(800, 300)
    view.show()
    app.exec_()

我会得到这个(你可以在下面的快照中看到问题):

问题 2)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    view = Editor()
    set_state1(view)
    set_state2(view)
    view.move(1000, 100)
    view.resize(800, 300)
    view.show()
    app.exec_()

如何修改代码以便在按下 ctrl+z 时能够恢复 state1?

现在使用 ctrl+z 时无法获取 state1:​​

主要是因为setText 的行为方式:

用文本替换所有当前文本。请注意,撤消/重做 此函数清除历史记录。

我已经尝试了undo and redo 文档中发布的一些功能,但到目前为止还没有成功。

例如,我的一个尝试是首先选择所有文本,然后使用replaceSelectedText,最后手动从以前的状态恢复选择,结果很丑(我不希望编辑器在撤消时滚动混乱/redoing)...基本上,我想得到和SublimeText一样的感觉。

顺便说一句,这是一个小例子,但在实际情况下,我会积累一堆操作而不经常提交闪烁...这就是为什么我有兴趣弄清楚如何回滚到以前的使用可撤消的 setText 时的状态... 否则,我想避免使用 Scintilla 函数,例如 insertAt、replaceSelectedText 或类似函数...因为我使用 python 字符串内置函数在内部修改缓冲区。

编辑:

我很确定 beginUndoAction 和 endUndoAction 不会帮助我回答问题 2,但是……SCI_ADDUNDOACTION 呢?尽管docs 非常令人困惑...:/

【问题讨论】:

    标签: python sublimetext3 pyqt5 scintilla qscintilla


    【解决方案1】:

    问题 1: 最后添加的选择会自动设置为Main 选择。要删除它,请在 set_state1 函数的末尾添加行 sci.SendScintilla(sci.SCI_SETMAINSELECTION, -1)

    问题 2

    • 您通过存储选择、使用replaceSelectedText、然后使用setCursorPosition / reselecting all selectionssetFirstVisibleLine 来恢复滚动位置来描述它的方式是一种方法。
    • 查看setText函数的C++源代码:
    // Set the given text.
    void QsciScintilla::setText(const QString &text)
    {
        bool ro = ensureRW();
    
        SendScintilla(SCI_SETTEXT, ScintillaBytesConstData(textAsBytes(text)));
        SendScintilla(SCI_EMPTYUNDOBUFFER);
    
        setReadOnly(ro);
    }
    

    您可以尝试使用sci.SendScintilla(sci.SCI_SETTEXT, b"some text") 设置文本,这不会重置撤消/重做缓冲区。

    【讨论】:

      猜你喜欢
      • 2012-10-02
      • 2021-06-01
      • 2014-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      • 1970-01-01
      相关资源
      最近更新 更多