Evgenii Legotckoi
Evgenii Legotckoi21. April 2018 16:18

Qt/C++ - Tutorial 076. Visualisierung mathematischer Formeln auf Qt

Kürzlich tauchte im Forum eine ziemlich interessante Frage auf, wie man Formeln in Qt visualisieren kann. Leider hatte ich lange Zeit keine Gelegenheit, mich mit der Seite und dem Forum zu beschäftigen, aber ich entschied, dass es sinnvoll wäre, auch nach einiger Zeit meine mögliche Vision des Problems zu präsentieren.

Die Frage ist, eine Formel zu visualisieren, die als Zeichenfolge geschrieben ist.

Geben Sie beispielsweise sqrt(5) in ein Eingabefeld ein, und in einigen Widgets wird eine grafische Darstellung der Quadratwurzel von 5 angezeigt, dh nicht das Ergebnis, sondern die Formel selbst. Ähnliche Funktionen sind in Latex und LibreOffice implementiert.

Es wird so aussehen.

Allein die Aufgabe, eine solche Funktion zu schreiben, kann meiner Meinung nach ziemlich schwierig und zeitaufwändig sein, insbesondere wenn es darum geht, eine Funktion mit verschachtelten Formeln usw. zu implementieren. Daher werde ich mich auf das Konzept konzentrieren, das mir in den Sinn gekommen ist, um die Anzeige der einfachsten Varianten von Formeln umzusetzen, d.h. ohne verschachtelte Teilformeln.


Allgemeine Bestimmungen

Um diese Funktionalität zu implementieren, benötigen Sie:

  • Markieren Sie den Formeleintrag mit regulären Ausdrücken
  • Formel auf Widget anzeigen

Ich glaube, dass für diese Aufgabe die Verwendung von regulären Ausdrücken durchaus geeignet ist, da Sie die Zeichenfolge korrekt analysieren und Instanzen von Formeln hervorheben müssen. Um eine grafische Darstellung der Formel zu erstellen, schreiben wir eine spezielle Klasse FormulaWidget , die einen regulären Ausdruck zum Suchen in der Formelleiste sowie eine Methode enthält, die die Formel an der angegebenen Stelle auf der Formelleiste zeichnet Widget mit dem QPainter-Objekt, das vom Widget selbst bereitgestellt wird. Diese Methode muss eine neue Position zurückgeben, um die nächste Formel zu zeichnen, damit sie sich nicht überlappen, wenn mehrere Formeln hintereinander übergeben werden.

Um Formeln zu zeichnen, erstellen wir eine von QWidget geerbte Klasse und überschreiben ihre paintEvent()-Methode, die für das Zeichnen des Inhalts dieses Widgets verantwortlich ist.

Hauptanwendungsfenster

Die von QWidget geerbte Klasse wird als Hauptfenster der Anwendung verwendet. Sie wählen es aus, wenn Sie ein Projekt erstellen. Es wird auch eine grafische Formulardatei haben, in der wir die Widgets platzieren müssen, an denen wir interessiert sind:

  • QLineEdit - wo wir die Formel schreiben
  • FormulaWidget - wo die Formel angezeigt wird

Im grafischen Editor müssen Sie ein reguläres Widget-Objekt hinzufügen und es über das Kontextmenü in die zuvor erstellte FormulaWidget -Klasse konvertieren. Im Kontextmenü gibt es dafür einen Punkt "Convert to ..." bzw. in der englischen Version "Promote to ...".

Ich werde den Inhalt der main.cpp-Datei nicht anfassen, da alles standardmäßig erstellt wird.

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

Widget.cpp

Um den eingegebenen Text an die Formel-Widgets zu übergeben, verwenden wir die signal textChanged-Verbindung von QLineEdit zum setFormula-Slot, den wir im FormulaWidget erstellen werden Klasse.

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->lineEdit, &QLineEdit::textChanged, ui->formulaWidget, &FormulaWidget::setFormula);
}

Widget::~Widget()
{
    delete ui;
}

Klassen zum Zeichnen von Formeln

Betrachten Sie nun die Klasse selbst zum Visualisieren von Formeln und die Klasse der Formel selbst. Diese beiden Klassen befinden sich in derselben Header-Datei ( FormulaWidget.h ) und Implementierungsdatei ( FormulaWidget.cpp ).

FormulaItem

FormelWidget.h

// Класс визуализации формулы
class FormulaItem
{
public:
    explicit FormulaItem(QString value) : m_value(value){}

    static const QString REGULAR_EXPRESSION; // Строка регулярного выражения для поиска формулы
    // Метод отрисовки формулы
    QPoint draw(const QPoint& pos, QPainter& p) const;

private:
    QString m_value; // Значение формулы
};

FormelWidget.cpp

const QString FormulaItem::REGULAR_EXPRESSION = "sqrt\\((?<value>\\d+)\\)";

QPoint FormulaItem::draw(const QPoint& pos, QPainter& p) const
{
    int valueWidth = p.fontMetrics().width(m_value);
    int valueHeight = p.fontMetrics().height();

    p.drawLine(pos.x(), 4 + valueHeight / 2, pos.x() + 5, 4 + valueHeight);
    p.drawLine(pos.x() + 5, 4 + valueHeight, pos.x() + 10, pos.y() + 1);
    p.drawLine(pos.x() + 10, pos.y() + 1, pos.x() + 14 + valueWidth, pos.y() + 1);

    p.drawText(QRect(pos.x() + 12, pos.y() + 4, pos.x() + 12 + valueWidth, pos.y() + 4 + valueHeight), m_value);
    return QPoint(pos.x() + valueWidth + 20, pos.y());
}

Die statische Konstantenvariable REGULAR_EXPRESSION ist eine Zeichenfolge, die einen regulären Ausdruck enthält, um nach einem Vorkommen einer Formel zu suchen.

Qt bietet zwei Klassen für die Arbeit mit regulären Ausdrücken:

  1. QRegExp – Ich habe es in einem Artikel über das Schreiben von HTML-Markup-Syntax-Highlighting verwendet.
  2. QRegularExpression - Ich habe noch keine Artikel darüber geschrieben, und dies wird der erste Artikel sein, der es verwendet

Die erste Klasse wurde früher eingeführt, die zweite wurde erst in Qt 5.0 eingeführt. Die erste ist, so wie ich es verstehe, Qts eigene Implementierung regulärer Ausdrücke. Und die zweite Klasse ist bereits eine Implementierung von regulären Ausdrücken mit Syntaxunterstützung ausschließlich für die Sprache Perl . Für den Moment empfiehlt die Dokumentation die Verwendung von QRegularExpression , und um die Syntax regulärer Ausdrücke zu lernen, studieren Sie die Perl -Dokumentation.

Was die gefürchtete Methode draw betrifft, so ist ihre Implementierung dafür verantwortlich, die Formel sauber zu zeichnen und die Position des Werts innerhalb der Quadratwurzel festzulegen. Es gibt genügend Pseudomathematik für die pixelweise Wiedergabe aller Linien und Zahlen mit dem Vorhandensein magischer Zahlen. Versuchen Sie in echten Projekten, dies zu vermeiden, und verwenden Sie benannte Konstanten wie PADDING_BOTTOM, OFFSET usw.

Einer der wichtigen Punkte in der draw -Methode ist, dass das QPainter -Objekt als Argument als Referenz übergeben werden muss, aber die Referenz kann nicht konstant sein, da dieses Objekt geändert wird. Hier ist also alles in Ordnung. Aus meiner eigenen Erfahrung werde ich sagen, dass dies normal ist, wenn mit dem Rendern von benutzerdefinierten Widgets gearbeitet wird, wenn ihr QPainter durch nicht konstante Referenz an andere Methoden übergeben wird.

Im obigen regulären Ausdruck gibt es einen benannten erfassten Wert, mit dem wir den Wert an der Wurzel extrahieren können, um ihn später zu zeichnen.

"sqrt\((? \d+)\)" - in diesem regulären Ausdruck ist dieser Name value .

FormelWidget

FormelWidget.h

// Класс для отрисовки всех формул
class FormulaWidget : public QWidget
{
    Q_OBJECT
    using BaseClass = QWidget;
public:
    explicit FormulaWidget(QWidget* parent = nullptr);

public slots:
    // Слот для установки формулы
    void setFormula(const QString& formula);

protected:
    virtual void paintEvent(QPaintEvent* event) override;

private:
    QList<FormulaItem> m_items;
};

Die Klasse hat zwei wichtige Methoden. Die erste dient zum Festlegen der Zeichenfolge, aus der wir die Formeln extrahieren, und die zweite überschriebene Methode ist paintEvent(). Die überschriebene Methode ist für das Zeichnen des Widgets verantwortlich, wir werden auch alle darin enthaltenen Formeln zeichnen. Diese Methode wird im Stack der Event-Handling-Methoden in Qt aufgerufen. Diese Methode wird nie direkt aufgerufen, sie wird aufgerufen, wenn bestimmte Ereignisse eintreten, aber um sie aufzurufen, reicht es aus, die Methode update(). aufzurufen.

FormelWidget.cpp

FormulaWidget::FormulaWidget(QWidget* parent) :
    BaseClass(parent)
{
    // Установим цвет фона виджета, по умолчанию он такой же, как в системном оформлении ОС
    QPalette pal = palette();
    pal.setColor(QPalette::Background, Qt::white);
    setAutoFillBackground(true);
    setPalette(pal);
}

void FormulaWidget::setFormula(const QString& formula)
{
    // Очищаем все формулы
    m_items.clear();

    // Создаём объект регулярного выражения для поиска формулы
    QRegularExpression sqrt_value(FormulaItem::REGULAR_EXPRESSION);
    // Ищем все вхождения формулы
    QRegularExpressionMatchIterator i = sqrt_value.globalMatch(formula);

    // создаём все объекты формул
    while (i.hasNext())
    {
        QRegularExpressionMatch match = i.next();
        if (match.hasMatch())
        {
            m_items.append(FormulaItem(match.captured("value")));
        }
    }

    // Запускаем перерисовку
    update();
}

void FormulaWidget::paintEvent(QPaintEvent* event)
{
    // Для перерисовки используется объект QPainter,
    // который обязательно должен получить объект за отрисовку которого он отвечает
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    p.setPen(Qt::black);

    QPoint formulaPos(2, 2);

    // Производим отрисовку всех формул, которые удалось найти
    for (const FormulaItem& item : m_items)
    {
        formulaPos = item.draw(formulaPos, p);
    }
}

Als Ergebnis dieses Codes wird die im Screenshot am Anfang des Artikels gezeigte Anwendung erhalten.

Ich füge auch den Projektcode bei. Herunterladen

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken