Форум сайта python.su
vanvanovАга, слона то и не заметил.
Наверху ссылки есть.
Офлайн
Вобщем ИМХО вы выбрали неудачный инструмент для решения вашей задачи. Tkinter весьма убог в плане возможностей по сравнению с тем же PyQt/PySide или WxPython.
Все что мы можем, это получить индекс текущей строки, и координаты начала строки/любого символа.
Соответвенно алгоритм прост, если У-координата строки слева больше У-координаты строки справа, нудно прокрутить левую сторону вверх, иначе прокрутить вниз.Вобщето можно(нужно) также контролировать и положения конца строки(на случай если “абзац” не будет полностью вмещаться в видимую область) и в случае чего ровняться по ней. Иначе начало строки уйдет вверх, TextWidget.bbox вернет None, и правая сторона не будет пролистываться.
А можно сравнивать координаты среднего символа в строке, и тогда оно будет равняться на середину, ну както так.
Примерный код, привел ниже, он конечно еще сырой и требует доработки, но думаю общий смысл вы уловите.
import sys from tkinter import * class Editor(Frame): # это все херня, просто бросаем виджеты на форму def __init__(self, master, **kwargs): Frame.__init__(self, master) if 'width' not in kwargs: kwargs['width'] = 30 self.left = Text(self, **kwargs) #Левый тексвиджет self.left['font']='Monoserif 12' self.left.pack(side=LEFT, fill=BOTH, expand=True) self.right = Text(self, **kwargs) #Правый тексвиджет self.right['font']='Monoserif 12' self.scrollbarLeft = Scrollbar(self) self.scrollbarLeft.pack(side=LEFT, fill=Y) self.left.config(yscrollcommand=self.scrollbarLeft.set) self.scrollbarLeft.config(command=self.left.yview) self.right.pack(side=LEFT, fill=BOTH, expand=True) self.scrollbarRight = Scrollbar(self) self.scrollbarRight.pack(side=RIGHT, fill=Y) self.right.config(yscrollcommand=self.scrollbarRight.set) self.scrollbarRight.config(command=self.right.yview) commands = '<Up>','<Down>','<Left>','<Right>' for command in commands: self.right.bind(command,self.cursorMoved) self.currentString = 0 self.markedString = 0 self.left.tag_config('bold',font='Monoserif 12 bold') self.right.tag_config('bold',font='Monoserif 12 bold') def cursorMoved(self,event): # курсор перемещаеться на следующую строку, подсвечивается следующая строка _pos = self.right.index(INSERT) pos = _pos.split('.') if self.currentString != pos[0]: self.currentString = pos[0] if self.currentString != self.markedString: self.left.tag_remove('bold',str(self.markedString)+'.0',str(self.markedString)+'.end') self.right.tag_remove('bold',str(self.markedString)+'.0',str(self.markedString)+'.end') self.markedString = self.currentString self.left.tag_add('bold',str(self.markedString)+'.0',str(self.markedString)+'.end') self.right.tag_add('bold',str(self.markedString)+'.0',str(self.markedString)+'.end') self.left.see(_pos) # тут начинаеться алгоритм подгонки строк leftStrPos = self.left.bbox(str(pos[0])+'.0') # координаты начала текущей строки справа rightStrPos = self.right.bbox(str(pos[0])+'.0') # координаты начала текущей строки слева if leftStrPos == None: # если символ невидим bbox возвращает None return True if rightStrPos == None: self.left.see(str(self.markedString)+'.0') return True leftY = leftStrPos[1] # У координата начала левой строки rightY = rightStrPos[1] # У координата начала правой строки if leftY - rightY > 0: # если леваяч строка ниже правой while leftY >= rightY+8 and self.left.yview()[1]<1: # пока левая строка ниже прапвой или пока не упремся в низ self.left.yview_scroll(1, 'unit') # сдвигаем левую строку на 1 строку вверх leftStrPos = self.left.bbox(str(pos[0])+'.0') # обновляем У координату левой строки leftY = leftStrPos[1] else: # иначе левая строка выше while leftY <= rightY-8 and self.left.yview()[0]>0: # пока левая строка выше правой или пока не упремся в верх self.left.yview_scroll(-1, 'unit') # сдвигаем левую строку 1 строку вниз leftStrPos = self.left.bbox(str(pos[0])+'.0') # обновляем У координату левой строки leftY = leftStrPos[1] if __name__ == '__main__': root = Tk() mainWin = Editor(root) mainWin.pack(fill=BOTH, expand=True) text1 = '''He broke the seal and glanced over the contents. "Oh, come, it may prove to be something of interest, after all." "Not social, then?" "No, distinctly professional." "And from a noble client?" "One of the highest in England." "My dear fellow. I congratulate you." ''' text1 = text1.splitlines() for i in range(len(text1)): text1[i] = (text1[i] + ' ') * 10 text1 = '\n'.join(text1) text2 = '''Он сломал печать и быстро просмотрел содержимое. "Э, нет, здесь всё-таки может оказаться кое-что интересное." "Значит, это не светское письмо?" "Нет, сугубо деловое." "От знатного клиента?" "Одного из самых знатных в Англии." "Поздравляю Вас, мой друг." ''' text2 = text2.splitlines() for i in range(len(text2)): text2[i] = (text2[i] + ' ') * 10 text2 = '\n'.join(text2) text1 = text1 * 5 text2 = text2 * 5 mainWin.left.insert(END,text1) mainWin.right.insert(END,text2) root.mainloop()
[code python][/code]
Отредактировано PEHDOM (Март 27, 2017 22:53:57)
Офлайн
MrViktor
PEHDOM
Спасибо! Буду разбираться.
Офлайн
PEHDOMПочти прочли мои мысли, но так как я с ним знаком поверхностно, то не стал этого озвучивать. Данная тема меня зацепила!
Tkinter весьма убог в плане возможностей
Прикреплённый файлы:
textEdit.zip (1,6 KБ)
Офлайн
В QEditText нумерация идет сквозная, не зависимо от к-ва строк и всего прочего, тоесть если у вас там текст из 1000 символов(не важно сколько у вас там строк или оно идет одной строкой) то первый символ будет иметь индекс 0 а последний 999. Перевод ствроки тоже символ. поэтому мы можем получить срез текста в видимой области, и уже с ним делать все что угодно. Подсчитывать колличество строк, символов, или символов в строке. Я прицепил обработку на событие cursorPositionChanged
при смене позиции курсора будет выводиться информация в консоль о к-ве видимых строк и их длинне.
#!-*-coding:utf-8-*- import sys # import PyQt4 QtCore and QtGui modules from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4 import uic (Ui_MainWindow, QMainWindow) = uic.loadUiType('textedit_test.ui') class MainWindow(QMainWindow): """MainWindow inherits QMainWindow""" def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) def countRow(self, doc): return doc.lineCount() def slot1(self): l1 = self.countRow(self.ui.textEdit.document()) self.ui.label.setText('Колличество строк: %s' %l1) def slot2(self): l2 = self.countRow(self.ui.textEdit_2.document()) self.ui.label_2.setText('Колличество строк: %s' %l2) def __del__(self): self.ui = None def cursorMoved(widget, name): #определяем размер области внутри границ виджета visibleArea = widget.contentsRect() #индекс символа в левом верхнем углу, я взял +4, но чтобы почти-/полу-скрытиый текст не попадал в выборку нужно добавлять высоту шрифта. startPos = widget.cursorForPosition(QPoint(visibleArea.x()+4,visibleArea.y()+4)).position() #индекс символа в правом нижнем углу(или любой крайний символ в последней строчке) чтобы почти-/полу-скрытиый текст не попадал в выборку нужно вычитать высоту шрифта. endPos = widget.cursorForPosition(QPoint(visibleArea.width()-4,visibleArea.height()-4)).position() #получаем срез видимого текста, первод строки это тоже символ visibleText = widget.toPlainText()[startPos:endPos] #print('Visible text from position {} to position {}:\n "{}"'.format(startPos,endPos, visibleText)) strings = visibleText.split('\n') #разбиваем строку на подстроки по символу \n print('Widget {} has {} visible strings.'.format(name , len(strings))) result = list() for i, string in enumerate(strings): result.append('string: {}, len: {}'.format(i, len(string))) print(result) #-----------------------------------------------------# if __name__ == '__main__': # create application app = QApplication(sys.argv) app.setApplicationName('test_my') # create widget w = MainWindow() w.setWindowTitle('test_my') w.ui.textEdit.setText('Первая строка текста') w.ui.textEdit.append('Вторая строка текста') w.ui.textEdit_2.setText('Очень длинная строка текста, такая длинная, что не помещается в одну строку') doc1 = w.ui.textEdit.document() w.ui.label.setText('Колличество строк: %s'%w.countRow(doc1)) doc2 = w.ui.textEdit_2.document() w.ui.label_2.setText('Колличество строк: %s' % w.countRow(doc2)) w.show() # connection QObject.connect(app, SIGNAL('lastWindowClosed()'), app, SLOT('quit()')) textEdit2 = w.ui.textEdit_2 textEdit2.cursorPositionChanged.connect(lambda: cursorMoved(textEdit2,'Right')) textEdit1 = w.ui.textEdit textEdit1.cursorPositionChanged.connect(lambda: cursorMoved(textEdit1,'Left')) # execute application sys.exit(app.exec_())
Widget Left has 2 visible strings. ['string: 0, len: 20', 'string: 1, len: 20'] Widget Right has 1 visible strings. ['string: 0, len: 75'] Exit code: 0
[code python][/code]
Отредактировано PEHDOM (Март 28, 2017 12:03:50)
Офлайн
PEHDOMНемного не то. В результате выводится, что в правом QTextEdit - содержится одна строка текста (по идее так и есть), но если ее длинна больше видимой области QTextEdit осуществляется перенос текста на следующую “визуальную” строку и таким образом мы видим наш текст в трех строках - так вот как вычислить сколько “визуальных” строк займет тест в QTextEdit?
позиции курсора будет выводиться информация в консоль о к-ве видимых строк и их длинне.
Офлайн
логика по сути таже самая, только берем начало-конец строки а не всего виджета. поменяйте cursorMoved на:
def cursorMoved(widget, name): #определяем размер области внутри границ виджета visibleArea = widget.contentsRect() cursor = widget.cursorRect() #текущая паозиция и размер кусора startPos = widget.cursorForPosition(QPoint(visibleArea.x(),cursor.y())).position() # начало визуальной строки endPos = widget.cursorForPosition(QPoint(visibleArea.width(),cursor.y())).position() #конец визуальной строки string = widget.toPlainText()[startPos:endPos] print('visual string is:',string)
>>> visual string is: Очень длинная строка текста, такая длинная, что не visual string is: помещается в одну строку
[code python][/code]
Отредактировано PEHDOM (Март 28, 2017 13:59:52)
Офлайн
PEHDOMСразу не догнал, что пытались донести, глянул на вывод первого вашего примера и подумал: “Нафига так муторно получать длину текста”
логика по сути таже самая, только берем начало-конец строки а не всего виджета. поменяйте cursorMoved на:
Офлайн
MrViktorэто не длинна текста, это длинна отображаемого текста , учитывает только то что мы видим глазами.
“Нафига так муторно получать длину текста”
[code python][/code]
Офлайн
PEHDOMТеперь-то я это понял, уже первый пример детальней разобрал
это не длинна текста, это длинна отображаемого текста , учитывает только то что мы видим глазами.
textEdit.document().begin().layout().lineCount()
Отредактировано MrViktor (Март 28, 2017 15:16:24)
Офлайн