问题
- Text editor: Sublime Text 3
- Python Version: 3.6
- UTF-8
- PyQt5
I am making a notepad in PyQt5 and I am making an option to be able to navigate between the lines and, of course, I need to move the text editor cursor so that it is in the line that the user wants, and the problem is that, nose how to move the cursor of a TextEdit. I have used several methods and none works. Simply or does not move the cursor or an error jumps.
This is the full code: https://github.com/MasPot4/Bloc-de-Notas
This is the part of the error
import sys
from PyQt5 import QtGui
from PyQt5.QtGui import QTextCursor
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QMainWindow, QApplication, QTextEdit, QMessageBox, QLabel, QPushButton
from PyQt5.QtWidgets import QHBoxLayout, QWidget, QMenu, QAction, QFileDialog, QLineEdit
import tkinter
root = tkinter.Tk()
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
class textEdit(QTextEdit):
def __init__(self):
super(textEdit, self).__init__()
self.cursor = self.textCursor()
class gotolineWin(QMainWindow):
def __init__(self):
super(gotolineWin, self).__init__()
self.main = textEdit()
self.label = QLabel(self)
self.go_line = QLineEdit(self)
self.buttonGoto = QPushButton("Go to...", self)
self.buttonCancel = QPushButton("Cancel", self)
self.initUi()
def initUi(self):
self.label.setText("Go to...")
self.label.move(20, 0)
self.go_line.move(20, 25)
self.go_line.resize(260, 20)
self.buttonGoto.move(20, 60)
self.buttonGoto.resize(100, 30)
self.buttonGoto.clicked.connect(lambda: self.GoToLine(int(self.go_line.text())))
self.buttonCancel.clicked.connect(self.cancel)
self.buttonCancel.move(180, 60)
self.setGeometry((width / 2) - 150, (height / 2) - 50, 300, 100)
self.setWindowTitle("Go to...")
def GoToLine(self, line):
# self.main.cursor = self.main.textCursor()
# self.main.cursor.movePosition(self.main.cursor.Left, self.main.cursor.KeepAnchor, 3)
# self.main.setTextCursor(self.main.cursor)
ln = int(line)
linecursor = QTextCursor(self.main.document().findBlockByLineNumber(ln - 1))
self.main.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
self.main.setTextCursor(linecursor)
self.close()
def cancel(self):
self.close()
class writter(QMainWindow):
def __init__(self):
super().__init__()
self.textEdit = textEdit()
self.lineWin = gotolineWin()
self.setCentralWidget(self.textEdit)
self.file_name = None
self.initUi()
def initUi(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
editMenu = menubar.addMenu('Edit')
formatMenu = menubar.addMenu('Format')
viewMenu = menubar.addMenu("View")
# File Menu
new_file = QAction('New', self)
new_file.setShortcut("Ctrl+N")
new_file.triggered.connect(self.newfile)
open_file = QAction('Open...', self)
open_file.setShortcut("Ctrl+O")
open_file.triggered.connect(self.openfile)
save_file = QAction('Save', self)
save_file.setShortcut("Ctrl+S")
save_file.triggered.connect(self.savefile)
save_as_file = QAction('Save As...', self)
save_as_file.setShortcut("Ctrl+Shift+S")
save_as_file.triggered.connect(self.saveasfile)
exit = QAction("Exit", self)
exit.triggered.connect(self.quit)
# Edit Menu
undo_edit = QAction("Undo", self)
undo_edit.setShortcut("Ctrl+Z")
undo_edit.triggered.connect(self.undo)
cut_edit = QAction("Cut", self)
cut_edit.setShortcut("Ctrl+X")
cut_edit.triggered.connect(self.cut)
copy_edit = QAction("Copy", self)
copy_edit.setShortcut("Ctrl+C")
copy_edit.triggered.connect(self.copy)
paste_edit = QAction("Paste", self)
paste_edit.setShortcut("Ctrl+V")
paste_edit.triggered.connect(self.paste)
delete_edit = QAction("Delete", self)
delete_edit.setShortcut("Supr")
delete_edit.triggered.connect(self.delete)
goto_edit = QAction("Go To...", self)
goto_edit.setShortcut("Ctrl+T")
goto_edit.triggered.connect(self.gotoline)
find_editor = QAction("Find", self)
find_editor.setShortcut("Ctrl+F")
select_all_edit = QAction("Select All", self)
select_all_edit.setShortcut("Ctrl+E")
time_edit = QAction("Date and Time", self)
time_edit.setShortcut("F5")
# Format Menu
font_format = QAction("Font", self)
# View Menu
zoom_view = QMenu("Zoom", self)
zoom_mas_view = QAction("Zoom In", self)
zoom_mas_view.setShortcut("Ctrl++")
zoom_menos_view = QAction("Ward Off", self)
zoom_menos_view.setShortcut("Ctrl+-")
zoom_pre_view = QAction("Restore Default Zoom", self)
zoom_pre_view.setShortcut("Ctrl+0")
zoom_view.addAction(zoom_mas_view)
zoom_view.addAction(zoom_menos_view)
zoom_view.addAction(zoom_pre_view)
statusbar_view = QAction("Status Bar", self)
fileMenu.addAction(new_file)
fileMenu.addAction(open_file)
fileMenu.addAction(save_file)
fileMenu.addAction(save_as_file)
fileMenu.addSeparator()
fileMenu.addAction(exit)
editMenu.addAction(undo_edit)
editMenu.addSeparator()
editMenu.addAction(cut_edit)
editMenu.addAction(copy_edit)
editMenu.addAction(paste_edit)
editMenu.addAction(delete_edit)
editMenu.addSeparator()
editMenu.addAction(goto_edit)
editMenu.addAction(find_editor)
editMenu.addSeparator()
editMenu.addAction(select_all_edit)
editMenu.addAction(time_edit)
viewMenu.addMenu(zoom_view)
viewMenu.addAction(statusbar_view)
self.setGeometry((width / 2) - 300, (height / 2) - 250, 600, 500)
self.setWindowTitle("NotePad 2.0")
self.show()
def newfile(self):
if self.textEdit.toPlainText() != "":
buttonReply = QMessageBox.question(self, 'Bloc de Notas 2.0', f"You want to save changes to Sin Titulo?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if buttonReply == QMessageBox.Yes:
self.saveasfile()
else:
try:
name, _ = QFileDialog.getSaveFileName(self, "New File", "New File.txt", "All Files (*.*)")
url = QUrl.fromLocalFile(name)
name = url.fileName()
with open(name, "w") as f:
f.write("")
self.textEdit.clear()
self.file_name = name
except FileNotFoundError:
pass
else:
try:
name, _ = QFileDialog.getSaveFileName(self, "New File", "New File.txt", "All Files (*.*)")
url = QUrl.fromLocalFile(name)
name = url.fileName()
with open(name, "w") as f:
f.write("")
self.textEdit.clear()
self.file_name = name
except FileNotFoundError:
pass
def openfile(self):
if self.textEdit.toPlainText() != "":
buttonReply = QMessageBox.question(self, 'Bloc de Notas 2.0', f"You want to save changes to Sin Titulo?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if buttonReply == QMessageBox.Yes:
self.saveasfile()
else:
try:
name, _ = QFileDialog.getOpenFileName(self, "New File", "New File.txt", "All Files (*.*)")
url = QUrl.fromLocalFile(name)
name = url.fileName()
with open(name, "r") as f:
content = f.read()
self.textEdit.setText(content)
except FileNotFoundError:
pass
else:
try:
name, _ = QFileDialog.getOpenFileName(self, "New File", "New File.txt", "All Files (*.*)")
url = QUrl.fromLocalFile(name)
name = url.fileName()
with open(name, "r") as f:
content = f.read()
self.textEdit.setText(content)
except FileNotFoundError:
pass
def savefile(self):
if self.textEdit.toPlainText() == "":
self.newfile()
elif self.textEdit.toPlainText() != "":
if self.file_name == None:
self.saveasfile()
else:
with open(self.file_name, "w") as f:
f.write(self.textEdit.toPlainText())
elif self.file_name == None:
self.saveasfile()
def saveasfile(self):
try:
name, _ = QFileDialog.getSaveFileName(self,'Save File', "New File.txt", "All Files (*.*)")
with open(name, "w") as f:
f.write(self.textEdit.toPlainText())
self.file_name = name
except FileNotFoundError:
pass
def quit(self):
sys.exit()
def undo(self):
self.textEdit.undo()
def cut(self):
self.textEdit.copy()
self.textEdit.insertPlainText("")
def copy(self):
self.textEdit.copy()
def paste(self):
text = QApplication.clipboard().text()
self.textEdit.insertPlainText(text)
def delete(self):
self.textEdit.insertPlainText("")
def gotoline(self):
self.lineWin.show()
app = QApplication(sys.argv)
Window = writter()
sys.exit(app.exec_())
回答1:
You are creating another QTextEdit within the gotolineWin widget and that is unnecessary, plus you are moving the cursor of the QTextEdit that is not the QTextEdit shown in the QMainWindow. Considering this, I have created a QDialog that should only receive the QTextEdit that adds the functionality you want.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class GoToDialog(QtWidgets.QDialog):
gotoSignal = QtCore.pyqtSignal(int)
def __init__(self, text_edit, parent=None):
super().__init__(parent)
self.m_text_edit = text_edit
self.spinbox = QtWidgets.QSpinBox(minimum=1)
self.m_text_edit.document().blockCountChanged.connect(self.spinbox.setMaximum)
self.spinbox.setMaximum(self.m_text_edit.document().blockCount())
self.buttonGoto = QtWidgets.QPushButton("Go to...")
self.buttonGoto.clicked.connect(self.onAccepted)
self.buttonCancel = QtWidgets.QPushButton("Cancel")
self.buttonCancel.clicked.connect(self.reject)
vlay = QtWidgets.QVBoxLayout(self)
hlay = QtWidgets.QHBoxLayout()
hlay.addWidget(self.buttonGoto)
hlay.addWidget(self.buttonCancel)
vlay.addWidget(QtWidgets.QLabel("Go to..."))
vlay.addWidget(self.spinbox)
vlay.addLayout(hlay)
self.setFixedSize(300, 100)
def onAccepted(self):
n = self.spinbox.value() - 1
if 0 <= n < self.m_text_edit.document().blockCount():
cursor = QtGui.QTextCursor(
self.m_text_edit.document().findBlockByLineNumber(n)
)
self.m_text_edit.setTextCursor(cursor)
self.reject()
class Writter(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.text_edit = QtWidgets.QTextEdit()
self.setCentralWidget(self.text_edit)
self.goto_dialog = GoToDialog(self.text_edit, self)
menubar = self.menuBar()
editMenu = menubar.addMenu("Edit")
goto_edit = QtWidgets.QAction("Go To...", self)
goto_edit.setShortcut("Ctrl+T")
goto_edit.triggered.connect(self.goto_dialog.show)
editMenu.addAction(goto_edit)
self.resize(600, 500)
self.center()
def center(self):
self.setGeometry(
QtWidgets.QStyle.alignedRect(
QtCore.Qt.LeftToRight,
QtCore.Qt.AlignCenter,
self.size(),
QtWidgets.qApp.desktop().availableGeometry(),
)
)
def main():
app = QtWidgets.QApplication(sys.argv)
w = Writter()
w.show()
return app.exec_()
if __name__ == "__main__":
sys.exit(main())
来源:https://stackoverflow.com/questions/57263368/move-cursor-line-position-qtextedit