自動インデントは、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 ---'''
このアプローチのもう 1 つの利点は、柔軟性が高いことです。レクサーで自動インデントをオンにすると、次のいずれかを選択できます (または組み合わせることもできます)。
QsciScintilla.AiOpening
QsciScintilla.AiClosing
QsciScintilla.AiMaintain
3. 問題
最初の段落で説明した方法は、レクサーを使用せずに機能します。lexer を使用した 2 番目の段落で説明したアプローチはそうではありません。へのパラメータとしてどの設定を選択して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 の私の Web サイトからこの例を取り上げました (そして、この質問のニーズに合わせて少し調整しました): https://qscintilla.com/custom-lexer-example/
5. メモ
完全を期すために、これは私のシステムです。
- ウィンドウズ10
- パイソン3.6
- QScintilla 2.10 以降