IscanderChe
IscanderChe15. Juni 2020 06:51

Ein einfacher Texteditor in Ultimate ++

Ich habe durch Zufall von Ultimate++ ( https://www.ultimatepp.org/ ) erfahren, als ich in einem IT-RSS-Feed über das nächste Update dieses Frameworks gelesen habe. Nun, dachte ich, da meine Stiftprojekte auf Eis liegen, warum nicht etwas Neues ausprobieren.

Ultimate++ (abgekürzt als U++ oder UPP) ist ein plattformübergreifendes Framework zur Entwicklung von GUI-Anwendungen auf Basis von C++. Neben dem Code des Frameworks selbst enthält es einen eigenen BLITZ-Assembler und die Entwicklungsumgebung TheIDE zum Bearbeiten von Code und GUI-Elementen.

Lassen Sie uns versuchen, einen einfachen Editor auf Basis von U++ zu schreiben.


Wir laden das Zip-Archiv mit dem Framework von der Seite herunter, entpacken es in ein beliebiges Verzeichnis und starten die TheIDE-Entwicklungsumgebung.
Als Erstes fordert Sie die Umgebung auf, ein Paket auszuwählen oder ein neues Anwendungspaket zu erstellen. Es gibt noch eine weitere Option - um eine neue Sammlung (Assembly) von Paketen zu erstellen. Sie können auch vorhandene Sammlungen auswählen. Aus bestehenden Sammlungen stehen verschiedene Beispiele zur Verfügung.

Lassen Sie uns also eine neue Sammlung erstellen. Dazu müssen Sie im Bereich Sammlungen das Kontextmenü aufrufen und den Punkt „Neue Baugruppe“ (Neue Sammlung) auswählen. Das sich öffnende Fenster hat drei Inline-Eingabefelder: „Package nests“, „Output directory“, „Assembly name“. Bei "Paketverschachtelungen" ist es besser, bereits eingetragene Pfade zu Paketen nicht zu löschen. Aber Sie müssen Ihren Pfad hinzufügen. Wir rufen den Paketverschachtelungseditor auf, indem wir auf die Schaltfläche mit den Auslassungspunkten rechts neben dem Eingabefeld klicken. Geben Sie im sich öffnenden Fenster einen bequemen Pfad zu Ihren Dateien ein, verschieben Sie diesen Pfad mit den Pfeiltasten an die erste Stelle und klicken Sie auf „OK“. Im "Ausgabeverzeichnis" wiederum erstellen wir einen bequemen Pfad für Ausgabedateien nach dem Kompilieren und Verknüpfen. Und wir schreiben in den "Namen der Versammlung" den Namen, unter dem die Sammlung in der Liste der Sammlungen präsentiert wird. Alles, klicken Sie auf "OK".

Lassen Sie uns nun ein neues Paket erstellen. Klicken Sie dazu auf die Schaltfläche "Neues Paket" in der unteren rechten Ecke des Hauptfensters von TheIDE.
In dem sich öffnenden Dialogfeld gibt es mehrere Optionen zum Erstellen eines Pakets. Wählen Sie „U++ CtrlLib-Anwendung mit Hauptfenster“ aus, indem Sie die CtrlLib-Bibliothek verwenden, die unter anderem die für uns interessanten Bildschirm-Widgets und das Layout des Hauptfensters enthält. Geben Sie den Namen des Pakets in das entsprechende Feld ein und klicken Sie auf "OK".

Danach öffnet sich das Hauptfenster von TheIDE.
Oben links befindet sich ein Fenster, in dem andere mit dem Paket verbundene Pakete angezeigt werden. Unten links ist ein Fenster mit den neu generierten Dateien unseres Pakets. Die Struktur der aktuellen Paketdatei wird rechts angezeigt. In der Mitte befindet sich der Code-Editor.
Es gibt insgesamt drei Dateien: UppNotepad2.h , main.cpp und UppNotepad2.lay . Ich werde Fragen warnen, warum „2“: Ich habe mit der ersten Version des Editors einen Fehler gemacht, und bei der Auswahl des Pakettyps habe ich eine einfache Anwendung ohne das Hauptfenster angegeben, und die * .lay-Datei wurde nicht erstellt, und wir kann nicht darauf verzichten.

Mit den ersten beiden Dateien ist alles klar, das ist der Quellcode unseres Notebooks. Die dritte Datei, UppNotepad2.lay , ist das Layout des Hauptanwendungsfensters. Betrachten wir jeden von ihnen im Detail.

#ifndef _UppNotepad2_UppNotepad2_h
#define _UppNotepad2_UppNotepad2_h

#include <CtrlLib/CtrlLib.h>

using namespace Upp;

#define LAYOUTFILE <UppNotepad2/UppNotepad2.lay>
#include <CtrlCore/lay.h>

class UppNotepad2 : public WithUppNotepad2Layout<TopWindow>
{
public:
    typedef UppNotepad2 CLASSNAME;
    UppNotepad2();
};

#endif

#include "UppNotepad2.h"

UppNotepad2::UppNotepad2()
{
    CtrlLayout(*this);
}

GUI_APP_MAIN
{
    UppNotepad2().Run();
}

Dieser Code wird automatisch generiert und muss nicht bearbeitet werden.

Für das Layout gibt es zwei Ansichtsmodi: in grafischer und in Textform.

LAYOUT(ppNotepad2Layout, 200, 100)
END_LAYOUT

Es gibt auch eine vierte Datei, die sich im Paketverzeichnis befindet - UppNotepad2.upp . Diese Datei wird in TheIDE nicht angezeigt, sie wird nur benötigt, um das Paket zu bauen.

Beginnen wir mit der Entwicklung unserer Anwendung anhand des Layouts.
Bewegen Sie den Mauszeiger über das graue Layoutfeld und wählen Sie im Kontextmenü: „Editoren – DocEdit“. So erscheint das Textbearbeitungs-Widget im Layout. Richten wir es ein. Wählen Sie dazu das Widget aus. Unten im mittleren Teil erscheint ein Fenster mit den Eigenschaften des Elements. Rechts neben dem Elementtyp befindet sich ein Eingabefeld für den Widget-Namen. Geben wir dort "editor" ein.

Wir werden auch die Schriftart und -größe festlegen. Klicken Sie dazu auf das Eingabefeld „SetFont“ und legen Sie im sich öffnenden Dialog die Schriftart „Monospace“, Größe 12 fest.

Und konfigurieren Sie die Abhängigkeit der Elementposition von der Größe des Hauptfensters.

Kommen wir nun zur Header-Datei.

Lassen Sie uns die Elemente des Hauptfensters und der Variablen deklarieren:
- Menüleistenmenü — Dropdown-Menüleiste;
- ToolBar-Tool - Symbolleiste;
- StatusBar-Status — Statusleiste;
- String fileName — Name der bearbeiteten Datei;
- String loadText — geladener Dateitext.

Lassen Sie uns die folgenden Methoden für die Arbeit mit Text und Dateien deklarieren:
- void OpenCmd() - Datei öffnen;
- void SaveCmd() - Datei speichern;
- void SaveAsCmd() - Datei speichern unter;
- void ExitCmd() - Anwendung schließen;
- void CutCmd() - Text ausschneiden;
- void CopyCmd() - Text kopieren;
- void PasteCmd() - Text einfügen;
- void UndoCmd() - macht die letzte Aktion rückgängig;
- void RedoCmd() - letzte Aktion wiederholen.

Wir überschreiben auch die Methode virtual void Close() des Fensters TopWindow für den Fall, dass die Schaltfläche zum Schließen des Fensters gedrückt wird.

Und definieren Sie die Methoden, die das Menü basierend auf dem Bibliothekselement Bar bilden:
- void FileBar(Bar& bar) — Dateimenü/Werkzeugleiste;
- void EditBar(Bar& bar) — Menü/Symbolleiste bearbeiten;
- void MainBar(Bar& bar) - Symbolleiste;
- MainMenu (Bar& Bar) aufheben - Dropdown-Menü.

class UppNotepad2 : public WithUppNotepad2Layout<TopWindow>
{
public:
    typedef UppNotepad2 CLASSNAME;
    UppNotepad2();

    MenuBar menu;
    ToolBar tool;
    StatusBar status;
    String fileName;
    String loadText;

    void OpenCmd();
    void SaveCmd();
    void SaveAsCmd();
    void ExitCmd();

    void CutCmd();
    void CopyCmd();
    void PasteCmd();
    void UndoCmd();
    void RedoCmd();

    void FileBar(Bar& bar);
    void EditBar(Bar& bar);
    void MainBar(Bar& bar);
    void MainMenu(Bar& bar);

    virtual void Close();
};

Kommen wir zur Implementierungsdatei.
Die Methode UppNotepad2::OpenCmd() wird zum Öffnen von Dateien verwendet. Es verwendet den FileSel -Dialog, um Dateien auszuwählen, die Type -Methode des Dialogs, um die Anzeige von *.txt-Dateien zu konfigurieren, und die Get() -Methode, um den vollständigen Pfad zu erhalten Datei. Außerdem wird das Dienstprogramm FileIn verwendet, um die Datei zum Lesen zu öffnen, und das Dienstprogramm LoadFile wird verwendet, um die Datei in einen Texteditor zu laden.

void UppNotepad2::OpenCmd()
{
    FileSel fs;
    fs.Type("Текстовые файлы (*.txt)", "*.txt");
    if(fs.ExecuteOpen("Открыть файл"))
    {
        fileName = fs.Get();
        FileIn fi(fileName);
        if(!fi)
        {
            PromptOK("Не могу открыть файл!");
            return;
        }
        loadText = LoadFile(fileName);
        editor.Set(loadText);
    }
}

Die Methoden UppNotepad2::SaveCmd() und UppNotepad2::SaveAsCmd() verwenden das Hilfsprogramm SaveFile , um die Datei zu speichern.

void UppNotepad2::SaveCmd()
{
    if(!SaveFile(fileName, editor.Get()))
        PromptOK("Не могу сохранить файл!");
}

void UppNotepad2::SaveAsCmd()
{
    FileSel fs;
    fs.Type("Текстовые файлы (*.txt)", "*.txt");
    if(fs.ExecuteSaveAs("Сохранить файл как"))
    {
        fileName = fs.Get();
        if(!SaveFile(fileName, editor.Get()))
            PromptOK("Не могу сохранить файл!");
    }
}

Die ExitCmd() -Methode prüft, ob der Text geändert wurde, und fragt den Benutzer bei einer Änderung, ob der Text gespeichert werden soll. Wenn der Benutzer dem Speichern des Textes zustimmt, wird entweder SaveCmd() aufgerufen, wenn die Datei zuvor geöffnet wurde, oder SaveAsCmd() , wenn die Datei neu ist.

void UppNotepad2::ExitCmd()
{
    String curText = editor.Get();
    if(!(loadText == curText))
    {
        if(PromptOKCancel("Сохранить файл?"))
        {
            if(!fileName.IsEmpty())
                SaveCmd();
            else
                SaveAsCmd();
        }
    }
    Break();
}

void UppNotepad2::Close()
{
    ExitCmd();
}

Das Ausschneiden von Text sowie das Kopieren und Einfügen, das Rückgängigmachen einer Aktion und das Wiederholen einer Aktion werden mit den entsprechenden Methoden des DocEdit -Widgets durchgeführt. Das Widget hat auch Hotkeys für diese Aktionen.

void UppNotepad2::CutCmd()
{
    editor.Cut();
}

void UppNotepad2::CopyCmd()
{
    editor.Copy();
}

void UppNotepad2::PasteCmd()
{
    editor.Paste();
}

void UppNotepad2::UndoCmd()
{
    editor.Undo();
}

void UppNotepad2::RedoCmd()
{
    editor.Redo();
}

Betrachten Sie den Menüerstellungscode.
Die Add() -Methode ist für das Hinzufügen eines Dropdown-Menüelements und einer Symbolleistenschaltfläche verantwortlich und funktioniert je nach Argumenten unterschiedlich. Wird der Pfad zum Symbol angegeben, wie es zB beim Befehl „Speichern“ der Fall ist, dann wird sowohl der Dropdown-Menüeintrag als auch die Schaltfläche in der Symbolleiste angelegt. Wenn das Symbol nicht angegeben ist (siehe Befehl "Speichern unter..."), wird nur der Dropdown-Menüpunkt erstellt. Das Makro THISBACK ermöglicht es Ihnen, die entsprechende Methode mit dem erstellten Menüpunkt zu verbinden. Die Methode Help() enthält eine Zeichenfolge mit Kontexthilfe, die in der Statusleiste angezeigt wird. Die Methode Separator() fügt sowohl dem Dropdown-Menü als auch der Symbolleiste eine Trennleiste hinzu.

void UppNotepad2::FileBar(Bar& bar)
{
    bar.Add("Открыть", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\open.png"), THISBACK(OpenCmd)).Help("Открыть файл");
    bar.Add("Сохранить", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\save.png"), THISBACK(SaveCmd)).Help("Сохранить файл");
    bar.Add("Сохранить как...", THISBACK(SaveAsCmd)).Help("Сохранить как");
    bar.Add("Выйти", THISBACK(ExitCmd)).Help("Выход из программы");
}

void UppNotepad2::EditBar(Bar& bar)
{
    bar.Add("Вырезать (Ctrl + X)", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\cut.png"), THISBACK(CutCmd)).Help("Вырезать выделенный текст в буфер");
    bar.Add("Копировать (Ctrl + C)", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\copy.png"), THISBACK(CopyCmd)).Help("Копировать выделенный текст в буфер");
    bar.Add("Вставить (Ctrl + V)", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\paste.png"), THISBACK(PasteCmd)).Help("Вставить текст из буфера");
    bar.Separator();
    bar.Add("Отменить (Ctrl + Z)", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\undo.png"), THISBACK(UndoCmd)).Help("Отменить последнее действие");
    bar.Add("Повторить (Ctrl + Shift + Z)", StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\redo.png"), THISBACK(RedoCmd)).Help("Повторить последнее действие");
}

void UppNotepad2::MainBar(Bar& bar)
{
    FileBar(bar);
    bar.Separator();
    EditBar(bar);
}

void UppNotepad2::MainMenu(Bar& bar)
{
    bar.Add("Файл", THISBACK(FileBar));
    bar.Add("Редактировать", THISBACK(EditBar));
}

Betrachten Sie nun den Konstruktor UppNotepad2 .

UppNotepad2::UppNotepad2()
{
    // Устанавливаем лэйаут
    CtrlLayout(*this);

    loadText = "";

    // Устанавливаем цвет текста
    editor.SetColor(TextCtrl::INK_NORMAL, Color(255, 255, 255));
    // Устанавливаем цвет фона
    editor.SetColor(TextCtrl::PAPER_NORMAL, Color(0, 0, 0));
    // Убираем горизонатльную полосу, обозначающую конец файла
    editor.EofLine(false);

    // Устанавливаем заголовок окна, указываем, что окно будет изменяемым, с кнопками минимизации и развёртывания окна
    // и что окно будет развёрнуто максимально
    Title("Upp Notepad 2").Sizeable().MinimizeBox().MaximizeBox().Maximize(true);
    // Устанавливаем иконку заголовка окна
    Icon(StreamRaster::LoadFileAny("E:\\dev\\upp\\UppNotepad2\\images\\editor.png"));
    // Добавляем в окно выпадающее меню
    AddFrame(menu);
    // Добавляем разделитель выпадающего меню и панели инструментов
    AddFrame(TopSeparatorFrame());
    // Добавляем панель инструментов
    AddFrame(tool);
    // Добавляем строку состояния
    AddFrame(status);
    // Устанавливаем меню
    menu.Set(THISBACK(MainMenu));
    // Перенаправляем вывод Help() в строку состояния
    menu.WhenHelp = status;
    // Устанавливаем панель инструментов
    tool.Set(THISBACK(MainBar));
    tool.WhenHelp = status;
}

Um plattformspezifische Implementierungsdetails auszublenden, wird das Makro GUI_APP_MAIN anstelle der Funktion main() verwendet.

GUI_APP_MAIN
{
    UppNotepad2().Run();
}

Hier ist das Ergebnis der Ausführung des Codes.

Um ein Anwendungssymbol für den Desktop hinzuzufügen, müssen Sie die *.rc-Datei einschließen. Schreiben Sie dazu in einem beliebigen Texteditor die folgende Zeile:

9999 ICON "images/editor.ico"

und speichern Sie es in der Datei UppNotepad.rc im Quellverzeichnis unserer Anwendung. Rufen Sie als nächstes im TheIDE-Dateifeld das Kontextmenü auf und wählen Sie den Punkt „Paketverzeichnisdatei(en) einfügen“ und wählen Sie die neu erstellte Datei aus. Dies ist notwendig, damit die *.rc-Datei in das Paket gelangt und an der Paketzusammenstellung teilnimmt.

Schlussfolgerungen

Vorteile des Frameworks:
- Die Installation der Distribution ist nicht erforderlich, es genügt, das Zip-Archiv in ein geeignetes Verzeichnis zu entpacken, und alle Tools werden verfügbar;
- Umfangreiche Datenbank mit Beispielen;
- einfache Entwicklung;
- gute Dokumentation;
- Die Ausgabe ist eine einzelne ausführbare Datei, die keine Abhängigkeiten erfordert.

Mängel:
- Auf der Website ist es einfacher, die Suche auf der Website zu verwenden, als in einigen Fällen defekten Links zu folgen;
- ein geöffnetes Fenster TheIDE unterstützt nur ein geöffnetes übergeordnetes Projektpaket. Dies wird umgangen, indem zugelassen wird, dass eine zweite und weitere Instanzen von TheIDE geöffnet werden. In gewisser Weise ist es sogar noch bequemer, Sie können mit Alt + Tab zwischen den Fenstern wechseln.
- Im TheIDE-Texteditor funktioniert die automatische Vervollständigung nicht für Schlüsselwörter und Variablen, die Sie in einer neuen Zeile eingeben;
- GUI-Widgets können nur im Layout erstellt werden, sie können nicht über den Code erstellt werden;
- Intoleranz des Codes von Maschine zu Maschine. (Ich habe den Editorcode auf einem Computer geschrieben, ich habe den Code auf einem anderen Computer erneut überprüft. Als Ergebnis „fiel“ die rc-Datei und gab während der Kompilierung einen Fehler aus. Dies liegt daran, dass der absolute Pfad zur Datei wurde in der *.upp-Datei angegeben. Ich musste neu verbinden.)

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

Magst du es? In sozialen Netzwerken teilen!

Evgenii Legotckoi
  • 15. Juni 2020 07:08

виджеты GUI можно создать только в лэйауте, через код их создавать нельзя;

Это довольно сильный недостаток. Может всё-таки возможно из кода производить редактирование?

непереносимость кода с машины на машину.

Там наверняка можно задать относительный путь. Как бы это довольно детский недостаток для фреймворка. Должно было быть вылечено ещё на ранних стадиях.

Макрос THISBACK позволяет подключить соответствующий метод к создаваемому элементу меню

Не смотрели, что там внутри макроса? Там обычный callback на шаблонах?

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

IscanderChe
  • 15. Juni 2020 07:47
  • (bearbeitet)

Может всё-таки возможно из кода производить редактирование?

По примерам - только так. Но некоторые, сложные виджеты, реализованы как раз через код. После Qt, конечно, тёмный лес. :))

Там наверняка можно задать относительный путь.

Возможно, что я не той опцией на первой машине воспользовался. Сейчас стоит как относительный путь.

Не смотрели, что там внутри макроса? Там обычный callback на шаблонах?

Не смотрел.

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

Мультиязычность есть, но я подробно не разбирался.

Evgenii Legotckoi
  • 15. Juni 2020 07:51

Фигово, что подключение функций реализовано на макросах. Напоминает Qt4 с их SIGNAL и SLOT макросами.

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