0

自动缩进是 QScintilla 提供的一个非常好的功能。插入新行时,自动缩进将光标推到与前一个相同的缩进级别:

在此处输入图像描述

1.没有词法分析器
如果你没有安装词法分析器,你可以像这样轻松地打开这个功能:

self.__editor.setAutoIndent(True)

self.__editor在此代码行中是 的一个实例QsciScintilla(),因此它代表我代码中的实际编辑器。

 
2. 使用词法分析器
即使您激活了词法分析器,以前的方法仍然有效。但这不是一个很好的做法,因为词法分析器可能会覆盖该设置。所以更好的方法是删除之前的代码行,并在词法分析器中打开自动缩进:

class MyLexer(QsciLexerCustom):

    def __init__(self, parent):
        super(MyLexer, self).__init__(parent)
        [...]
        self.setAutoIndentStyle(QsciScintilla.AiMaintain)
    ''''''

    def language(self):
        [...]
    ''''''

    def description(self, style):
        [...]
    ''''''

    def styleText(self, start, end):
        [...]
    ''''''

'''--- end class ---'''

这种方法的另一个优点是更大的灵活性。在词法分析器中打开自动缩进让您可以选择(甚至组合):

  • QsciScintilla.AiOpening
  • QsciScintilla.AiClosing
  • QsciScintilla.AiMaintain

 
3.问题
第一段中描述的方法没有词法分析器有效。第二段中描述的使用词法分析器的方法没有。无论我选择哪个设置作为参数setAutoIndentStyle(..),都不会改变。
为什么?

4. 一个完整的实验示例
这里是一个实验示例。只需将其复制粘贴到.py文件中并运行即可。你应该得到一个带有一些简单语法高亮的工作编辑器。您可以使用它来试验自动缩进:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qsci import *
import re


class MyLexer(QsciLexerCustom):

    def __init__(self, parent):
        super(MyLexer, self).__init__(parent)

        # Default text settings
        # ----------------------
        self.setDefaultColor(QColor("#ff000000"))
        self.setDefaultPaper(QColor("#ffffffff"))
        self.setDefaultFont(QFont("Consolas", 14))

        # Initialize colors per style
        # ----------------------------
        self.setColor(QColor("#ff000000"), 0)   # Style 0: black
        self.setColor(QColor("#ff7f0000"), 1)   # Style 1: red
        self.setColor(QColor("#ff0000bf"), 2)   # Style 2: blue
        self.setColor(QColor("#ff007f00"), 3)   # Style 3: green

        # Initialize paper colors per style
        # ----------------------------------
        self.setPaper(QColor("#ffffffff"), 0)   # Style 0: white
        self.setPaper(QColor("#ffffffff"), 1)   # Style 1: white
        self.setPaper(QColor("#ffffffff"), 2)   # Style 2: white
        self.setPaper(QColor("#ffffffff"), 3)   # Style 3: white

        # Initialize fonts per style
        # ---------------------------
        self.setFont(QFont("Consolas", 14, weight=QFont.Bold), 0)   # Style 0: Consolas 14pt
        self.setFont(QFont("Consolas", 14, weight=QFont.Bold), 1)   # Style 1: Consolas 14pt
        self.setFont(QFont("Consolas", 14, weight=QFont.Bold), 2)   # Style 2: Consolas 14pt
        self.setFont(QFont("Consolas", 14, weight=QFont.Bold), 3)   # Style 3: Consolas 14pt

        # Auto indent
        # ------------
        #self.setAutoIndentStyle(QsciScintilla.AiOpening | QsciScintilla.AiClosing)
        self.setAutoIndentStyle(QsciScintilla.AiMaintain)
        print(self.autoIndentStyle())

    ''''''

    def language(self):
        return "SimpleLanguage"
    ''''''

    def description(self, style):
        if style == 0:
            return "myStyle_0"
        elif style == 1:
            return "myStyle_1"
        elif style == 2:
            return "myStyle_2"
        elif style == 3:
            return "myStyle_3"
        ###
        return ""
    ''''''

    def styleText(self, start, end):
        # 1. Initialize the styling procedure
        # ------------------------------------
        self.startStyling(start)

        # 2. Slice out a part from the text
        # ----------------------------------
        text = self.parent().text()[start:end]

        # 3. Tokenize the text
        # ---------------------
        p = re.compile(r"[*]\/|\/[*]|\s+|\w+|\W")

        # 'token_list' is a list of tuples: (token_name, token_len)
        token_list = [ (token, len(bytearray(token, "utf-8"))) for token in p.findall(text)]

        # 4. Style the text
        # ------------------
        # 4.1 Check if multiline comment
        multiline_comm_flag = False
        editor = self.parent()
        if start > 0:
            previous_style_nr = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1)
            if previous_style_nr == 3:
                multiline_comm_flag = True
            ###
        ###
        # 4.2 Style the text in a loop
        for i, token in enumerate(token_list):
            if multiline_comm_flag:
                self.setStyling(token[1], 3)
                if token[0] == "*/":
                    multiline_comm_flag = False
                ###
            ###
            else:
                if token[0] in ["for", "while", "return", "int", "include"]:
                    # Red style
                    self.setStyling(token[1], 1)

                elif token[0] in ["(", ")", "{", "}", "[", "]", "#"]:
                    # Blue style
                    self.setStyling(token[1], 2)

                elif token[0] == "/*":
                    multiline_comm_flag = True
                    self.setStyling(token[1], 3)

                else:
                    # Default style
                    self.setStyling(token[1], 0)
                ###
            ###
        ###

    ''''''

''' end Class '''




myCodeSample = r"""#include <stdio.h>
/*
 * This is a
 * multiline
 * comment */
int main()
{
    char arr[5] = {'h', 'e', 'l', 'l', 'o'};

    int i;
    for(i = 0; i < 5; i++) {
        printf(arr[i]);
    }
    return 0;
}""".replace("\n","\r\n")




class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()

        # -------------------------------- #
        #           Window setup           #
        # -------------------------------- #

        # 1. Define the geometry of the main window
        # ------------------------------------------
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("QScintilla Test")

        # 2. Create frame and layout
        # ---------------------------
        self.__frm = QFrame(self)
        self.__frm.setStyleSheet("QWidget { background-color: #ffeaeaea }")
        self.__lyt = QVBoxLayout()
        self.__frm.setLayout(self.__lyt)
        self.setCentralWidget(self.__frm)
        self.__myFont = QFont()
        self.__myFont.setPointSize(14)

        # 3. Place a button
        # ------------------
        self.__btn = QPushButton("Qsci")
        self.__btn.setFixedWidth(50)
        self.__btn.setFixedHeight(50)
        self.__btn.clicked.connect(self.__btn_action)
        self.__btn.setFont(self.__myFont)
        self.__lyt.addWidget(self.__btn)

        # -------------------------------- #
        #     QScintilla editor setup      #
        # -------------------------------- #

        # ! Make instance of QSciScintilla class!
        # ----------------------------------------
        self.__editor = QsciScintilla()
        self.__editor.setText(myCodeSample)     # 'myCodeSample' is a string containing some C-code
        self.__editor.setLexer(None)            # We install lexer later
        self.__editor.setUtf8(True)             # Set encoding to UTF-8
        self.__editor.setFont(self.__myFont)    # Gets overridden by lexer later on

        # 1. Text wrapping
        # -----------------
        self.__editor.setWrapMode(QsciScintilla.WrapWord)
        self.__editor.setWrapVisualFlags(QsciScintilla.WrapFlagByText)
        self.__editor.setWrapIndentMode(QsciScintilla.WrapIndentIndented)

        # 2. End-of-line mode
        # --------------------
        self.__editor.setEolMode(QsciScintilla.EolWindows)
        self.__editor.setEolVisibility(False)

        # 3. Indentation
        # ---------------
        self.__editor.setIndentationsUseTabs(False)
        self.__editor.setTabWidth(4)
        self.__editor.setIndentationGuides(True)
        self.__editor.setTabIndents(True)
        #self.__editor.setAutoIndent(True)   <- This is set in the lexer!!!

        # 4. Caret
        # ---------
        self.__editor.setCaretForegroundColor(QColor("#ff0000ff"))
        self.__editor.setCaretLineVisible(True)
        self.__editor.setCaretLineBackgroundColor(QColor("#1f0000ff"))
        self.__editor.setCaretWidth(2)

        # 5. Margins
        # -----------
        # Margin 0 = Line nr margin
        self.__editor.setMarginType(0, QsciScintilla.NumberMargin)
        self.__editor.setMarginWidth(0, "0000")
        self.__editor.setMarginsForegroundColor(QColor("#ff888888"))

        # -------------------------------- #
        #          Install lexer           #
        # -------------------------------- #
        self.__lexer = MyLexer(self.__editor)
        self.__editor.setLexer(self.__lexer)

        # ! Add editor to layout !
        # -------------------------
        self.__lyt.addWidget(self.__editor)
        self.show()

    ''''''

    def __btn_action(self):
        print("Hello World!")
    ''''''

''' End Class '''

if __name__ == '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Fusion'))
    myGUI = CustomMainWindow()

    sys.exit(app.exec_())

''''''

我已经从我在 QScintilla 上的网站上获取了这个例子(并稍微适应了这个问题的需要):https ://qscintilla.com/custom-lexer-example/

5.注意事项
为了完整起见,这是我的系统:

  • 视窗 10
  • 蟒蛇 3.6
  • QScintilla 2.10 或更高版本
4

1 回答 1

1

闪烁词法分析器有两部分,第一部分用于语法着色,第二部分用于缩进。

您使用的示例仅用于语法着色。

我没有使用 QScintilla 的 python 实现,所以不确定这些函数是否在 python 中可用,但是在 C++ 中,你可以在你的词法分析器中使用 indentLine 来设置它,或者设置词法分析器的 begin 和 endblock 关键字来让 qscintilla为你而做。

于 2017-05-14T14:37:44.333 回答