Как отображать диалоги в определенной позиции внутри виджета QScintilla?

Я получил этот простой фрагмент кода mcve:

import sys
import re

from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.Qsci import QsciScintilla
from PyQt5 import Qsci


class SimpleEditor(QsciScintilla):

    def __init__(self, language=None, parent=None):
        super().__init__(parent)

        font = QtGui.QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        fontmetrics = QtGui.QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(0, fontmetrics.width("00000") + 6)
        self.setMarginLineNumbers(0, True)
        self.setMarginsBackgroundColor(QtGui.QColor("#cccccc"))
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QtGui.QColor("#E8E8FF"))

        if language:
            self.lexer = getattr(Qsci, 'QsciLexer' + language)()
            self.setLexer(self.lexer)

        self.SendScintilla(QsciScintilla.SCI_FOLDALL, True)
        self.setAutoCompletionThreshold(1)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)

        # Signals/Slots
        self.cursorPositionChanged.connect(self.on_cursor_position_changed)
        self.copyAvailable.connect(self.on_copy_available)
        self.indicatorClicked.connect(self.on_indicator_clicked)
        self.indicatorReleased.connect(self.on_indicator_released)
        self.linesChanged.connect(self.on_lines_changed)
        self.marginClicked.connect(self.on_margin_clicked)
        self.modificationAttempted.connect(self.on_modification_attempted)
        self.modificationChanged.connect(self.on_modification_changed)
        self.selectionChanged.connect(self.on_selection_changed)
        self.textChanged.connect(self.on_text_changed)
        self.userListActivated.connect(self.on_user_list_activated)

    def on_cursor_position_changed(self, line, index):
        print("on_cursor_position_changed")

    def on_copy_available(self, yes):
        print('-' * 80)
        print("on_copy_available")

    def on_indicator_clicked(self, line, index, state):
        print("on_indicator_clicked")

    def on_indicator_released(self, line, index, state):
        print("on_indicator_released")

    def on_lines_changed(self):
        print("on_lines_changed")

    def on_margin_clicked(self, margin, line, state):
        print("on_margin_clicked")

    def on_modification_attempted(self):
        print("on_modification_attempted")

    def on_modification_changed(self):
        print("on_modification_changed")

    def on_selection_changed(self):
        print("on_selection_changed")

    def on_text_changed(self):
        print("on_text_changed")

    def on_user_list_activated(self, id, text):
        print("on_user_list_activated")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    ex = QtWidgets.QWidget()
    hlayout = QtWidgets.QHBoxLayout()
    ed = SimpleEditor("JavaScript")

    hlayout.addWidget(ed)

    ed.setText("""#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main( void ) {

    vec2 st = ( gl_FragCoord.xy / resolution.xy );
    vec2 lefbot = step(vec2(0.1), st);
    float pct = lefbot.x*lefbot.y;
    vec2 rigtop = step(vec2(0.1), 1.-st);
    pct *= rigtop.x*rigtop.y;
    vec3 color = vec3(pct);

    gl_FragColor = vec4( color, 1.0 );""")

    ex.setLayout(hlayout)
    ex.show()
    ex.resize(800, 600)

    sys.exit(app.exec_())

Я пытаюсь написать код, аналогичный тому, что представлен на этом сайте. Как видите, на этом сайте пользователь может изменять числовые значения, только щелкнув мышью, при этом появится небольшое диалоговое окно, и пользователь сможет изменять значения в режиме реального времени.

Теперь первое, что мне нужно выяснить, это какие сигналы мне нужно учитывать, когда пользователь нажимает на виджет QScintilla (я использую эти документы). Что это / те, которые я действительно должен заботиться об этом.

В любом случае, предполагая, что я использую правильный сигнал для всплывающего диалогового окна, содержащего несколько ползунков, как я могу определить правильное положение, в котором должно появиться мое диалоговое окно?


person BPL    schedule 23.09.2016    source источник
comment
Что в настоящее время мешает вам начать кодировать его самостоятельно? Вопросы по SO должны быть сосредоточены на одной конкретной проблеме программирования, иначе это будет выглядеть так, будто вы просите людей написать весь код за вас.   -  person ekhumoro    schedule 23.09.2016
comment
@ekhumoro Хорошо, я испачкал руки этой задачей, и я отредактировал свой вопрос, чтобы попытаться сделать его более конкретным, не могли бы вы подтвердить, что формат теперь более удобен? Кроме того, я избавился от всей кучи своих оффтоповых комментариев, чтобы ветка не засорялась. Надеюсь, что заголовок/содержание вопроса больше не являются широкими, пожалуйста, дайте мне знать. Спасибо.   -  person BPL    schedule 23.09.2016
comment
Спасибо, что потрудились улучшить свой вопрос.   -  person ekhumoro    schedule 23.09.2016


Ответы (1)


Сигнал cursorPositionChanged можно использовать для обнаружения того, когда мышь или клавиатура перемещают курсор в позицию внутри числа. Затем можно использовать регулярное выражение, чтобы найти, где число начинается и заканчивается в текущей строке. Получив это, вы можете использовать некоторые низкоуровневые функции для вычисления глобальной позиции числа.

Метод ниже использует этот подход для отображения всплывающей подсказки под соответствующим текстом:

def on_cursor_position_changed(self, line, index):
    text = self.text(line)
    for match in re.finditer('(?:^|(?<=\W))\d+(?:\.\d+)?(?=$|\W)', text):
        start, end = match.span()
        if start <= index <= end:
            pos = self.positionFromLineIndex(line, start)
            x = self.SendScintilla(
                QsciScintilla.SCI_POINTXFROMPOSITION, 0, pos)
            y = self.SendScintilla(
                QsciScintilla.SCI_POINTYFROMPOSITION, 0, pos)
            point = self.mapToGlobal(QtCore.QPoint(x, y))
            num = float(match.group())
            message = 'number: %s' % num
            break
    else:
        point = QtCore.QPoint(0, 0)
        message = ''
    QtWidgets.QToolTip.showText(point, message)
person ekhumoro    schedule 23.09.2016
comment
Большое спасибо! Этого более чем достаточно для начала. Следующим шагом будет создание различных виджетов для обработки всех различных типов, предлагаемых языком glsl (float, vec2, vec3), и их правильный анализ. Кстати, пара дополнительных быстрых вопросов, знаете ли вы, почему использование QtWidgets.QColorDialog.getColor() вместо QToolTip приведет к сбою? Кроме того, как лучше всего заменить текст в QScintilla? В любом случае, спасибо за хороший ответ, очень приятно ;-) - person BPL; 24.09.2016
comment
@БПЛ. Я думаю, вам придется опубликовать несколько новых вопросов по этим другим вопросам. - person ekhumoro; 24.09.2016