代码之家  ›  专栏  ›  技术社区  ›  BPL

使用qscintilla settext时如何撤消?

  •  0
  • BPL  · 技术社区  · 5 年前

    让我先发布一些小助手函数,我将使用这些函数来阐述我的问题:

    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_()
    

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

    enter image description here

    问题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:

    enter image description here

    主要是因为如何 setText 行为:

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

    我已经尝试了 undo and redo 但到目前为止还没有运气。

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

    顺便说一句,这是一个很小的例子,但在实际情况下,我将积累大量的操作,而不经常提交闪烁…这就是为什么我想知道当使用不可撤销的设置文本时如何回滚到以前的状态…否则,我想避免使用闪烁函数,例如 insertAt ,替换选定的文本或类似文本…因为我正在使用python字符串内置函数在内部修改缓冲区。

    编辑:

    我确信BeginUndoAction和EndUndoAction不会帮助我回答问题2,但是…怎么样 SCI_ADDUNDOACTION ?虽然 docs 但是很困惑…:

    1 回复  |  直到 5 年前
        1
  •  1
  •   Matic Kukovec    5 年前

    问题1 : 最后添加的选择将自动设置为 Main 选择。要删除它,请添加行 sci.SendScintilla(sci.SCI_SETMAINSELECTION, -1) set_state1 功能。

    问题2 :

    • 您通过存储选择来描述它的方式,使用 replaceSelectedText ,然后使用 setCursorPosition / reselecting all selections setFirstVisibleLine 恢复滚动位置是一种方法。
    • 看C++的源代码 setText 功能:
    // 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") ,这不会重置撤消/重做缓冲区。