Автор Тема: qtSimpleGraph  (Прочитано 5906 раз)

Оффлайн tema

  • alt linux team
  • ***
  • Сообщений: 2 073
qtSimpleGraph
« : 08.01.2021 08:29:24 »
Отделено от https://forum.altlinux.org/index.php?topic=41222.0

https://github.com/temaps/qtSimpleGraph
https://github.com/temaps/qtSimpleGraphPy
На самом деле, я уже давно вынашивал идею сделать подобное на Qt, чтобы получить все самые навороченные, новые и кроссплатформенные возможности
Так у Вас в примере как раз тоже кавычки.
#include "../qtsgraph.h"  :-)
Ну это пока идёт разработка  ;-)
Вот тут планируется вставить обработчики?
void QTSGraph::mousePressEvent(QMouseEvent *event)
{
    ResetTimer->stop();
    EventMouseClicked = true;
    if (event->buttons() & Qt::LeftButton)
    {
        // Левая кнопка
    }
    else if (event->buttons() & Qt::RightButton)
    {
        // Правая кнопка
    }
    ResetTimer->start(ResetInterval);
}
на первый взгляд, можно сменить тип EventMouseClicked и возвращать клавишу мышки результатом MouseClicked() (непрочитанные нажатия всё равно сейчас теряются).
Тут, я думал, сделать как с клавишами. Клавиши будут в отдельной переменной вроде IDMouseButton. EventMouseClicked нужен как факт нажатия для функции MouseClicked по аналогии с функцией KeyPressed. ReadKey и KeyPressed я взял из старого доброго модуля graph TP70  :-)
Здесь ещё опечатка в комментарии.
Спасибо! :-) Сейчас поправлю
« Последнее редактирование: 08.01.2021 08:49:01 от tema »

Оффлайн trs

  • Участник
  • *
  • Сообщений: 287
Re: qtSimpleGraph
« Ответ #1 : 09.01.2021 09:59:00 »
Ну это пока идёт разработка 
А потом будет пакет из заголовочного файла и разделяемая библиотека ради одного класса? А с чужими платформами как, с той же Виндос, dll собирать?
Клавиши будут в отдельной переменной вроде IDMouseButton. EventMouseClicked нужен как факт нажатия для функции MouseClicked по аналогии с функцией KeyPressed.
Вариант понятен. Просто я не уловил необходимость разделения на отдельные переменные. Факт нажатия можно получать из кода клавиш. Сейчас флажок по таймеру сбрасывается, а код остаётся -- для меня поведение выглядит неконсистентным и не ясно, зачем так.  :rolleyes:

Оффлайн tema

  • alt linux team
  • ***
  • Сообщений: 2 073
Re: qtSimpleGraph
« Ответ #2 : 09.01.2021 21:24:20 »
Ну это пока идёт разработка 
А потом будет пакет из заголовочного файла и разделяемая библиотека ради одного класса? А с чужими платформами как, с той же Виндос, dll собирать?
Для пакета можно поступить как с xcbwin - просто весь код из .cpp скопировать в конец .h и будет один файл. Пока не вижу проблем с windows, но сейчас проверю на всякий случай.
Клавиши будут в отдельной переменной вроде IDMouseButton. EventMouseClicked нужен как факт нажатия для функции MouseClicked по аналогии с функцией KeyPressed.
Вариант понятен. Просто я не уловил необходимость разделения на отдельные переменные. Факт нажатия можно получать из кода клавиш. Сейчас флажок по таймеру сбрасывается, а код остаётся -- для меня поведение выглядит неконсистентным и не ясно, зачем так.  :rolleyes:
Это сделано для того, чтобы добиться вот такой конструкции:
while(true)
{
    if(KeyPressed())
    {
       k = ReadKey();
       // Делаем что-то в зависимости от k
    }
    Delay(100);
}
С радостью приму предложения, как можно сделать это другим способом.
Вообще я хотел сделать стэк нажатых клавиш и кликов мыши, чтобы не терять те, которые не успел обработать во время Delay, например.
« Последнее редактирование: 09.01.2021 23:47:55 от tema »

Оффлайн tema

  • alt linux team
  • ***
  • Сообщений: 2 073
Re: qtSimpleGraph
« Ответ #3 : 09.01.2021 23:46:14 »
Пока не вижу проблем с windows, но сейчас проверю на всякий случай.
Проверил. Проблем нет. На Windows тоже всё работает

Оффлайн trs

  • Участник
  • *
  • Сообщений: 287
Re: qtSimpleGraph
« Ответ #4 : 10.01.2021 11:04:13 »
Для пакета можно поступить как с xcbwin - просто весь код из .cpp скопировать в конец .h и будет один файл. Пока не вижу проблем с windows, но сейчас проверю на всякий случай.
В windows так и делают, объединяю библиотеку как header-only. Там нет заботливых мантайнеров.

Это сделано для того, чтобы добиться вот такой конструкции:
while(true)
{
    if(KeyPressed())
    {
       k = ReadKey();
       // Делаем что-то в зависимости от k
    }
    Delay(100);
}

Я, наверное, что-то упускаю. Поскольку EventMouseClicked можно удалить, примерно так:
diff --git a/qtsgraph.cpp b/qtsgraph.cpp
index 83a4ab4..403302f 100644
--- a/qtsgraph.cpp
+++ b/qtsgraph.cpp
@@ -112,9 +112,7 @@ void QTSGraph::Circle(int x, int y, int radius)
 bool QTSGraph::MouseClicked()
 {
     QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
-    bool m = EventMouseClicked;
-    EventMouseClicked = false;
-    return m;
+    return IDMouseButton != Qt::NoButton;
 }

 void QTSGraph::OutTextXY(int x, int y, std::string caption)
@@ -159,15 +157,15 @@ int QTSGraph::ReadKey()
     return t;
 }

-int QTSGraph::ReadMouseButton()
+Qt::MouseButtons QTSGraph::ReadMouseButton()
 {
-    if(IDMouseButton == -1)
+    if(IDMouseButton == Qt::NoButton)
     {
         while(!MouseClicked() && this->isVisible())
             Delay(1);
     }
-    int t = IDMouseButton;
-    IDMouseButton = -1;
+    Qt::MouseButtons t = IDMouseButton;
+    IDMouseButton = Qt::NoButton;
     return t;
 }

@@ -246,7 +244,7 @@ void QTSGraph::slotResetTimer()
 {
     ResetTimer->stop();
     EventKeyPressed = false;
-    EventMouseClicked = false;
+    IDMouseButton = Qt::NoButton;
 }

 void QTSGraph::paintEvent(QPaintEvent *event)
@@ -258,22 +256,7 @@ void QTSGraph::paintEvent(QPaintEvent *event)
 void QTSGraph::mousePressEvent(QMouseEvent *event)
 {
     ResetTimer->stop();
-    EventMouseClicked = true;
-    if (event->buttons() & Qt::LeftButton)
-    {
-        // Левая кнопка
-        IDMouseButton = 1;
-    }
-    else if (event->buttons() & Qt::RightButton)
-    {
-        // Правая кнопка
-        IDMouseButton = 2;
-    }
-    else if (event->buttons() & Qt::MiddleButton)
-    {
-        // Средняя кнопка
-        IDMouseButton = 3;
-    }
+    IDMouseButton = event->buttons();
     ResetTimer->start(ResetInterval);
 }

diff --git a/qtsgraph.h b/qtsgraph.h
index 5b02e45..d23a13f 100644
--- a/qtsgraph.h
+++ b/qtsgraph.h
@@ -81,7 +81,7 @@ public:
     void OutTextXY(int x, int y, std::string caption);
     void PutPixel(int x, int y, QRgb c = 0x00000000, int PenWidth = 1);
     int ReadKey();
-    int ReadMouseButton();
+    Qt::MouseButtons ReadMouseButton();
     void Rectangle(int x1, int y1, int x2, int y2);
     void SetColor(const QColor &c = Qt::black);
     void SetColor(const QRgb c = 0x00000000);
@@ -128,10 +128,9 @@ private slots:
     void slotStartTimer();

 private:
-    bool EventMouseClicked = false;
     bool EventKeyPressed = false;
     int IDPressedKey = -1;
-    int IDMouseButton = -1;
+    Qt::MouseButtons IDMouseButton = Qt::NoButton;
     int ResetInterval;
     int TextDirection = 0;

При этом пример с мышкой работает без существенных изменений. Код средней кнопки изменился с 3 на 4, поскольку может быть нажато несколько кнопок.
diff --git a/main.cpp b/main.cpp
index 67d6ba8..91545f7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -30,13 +30,16 @@ void QTSGraph::PaintBox()
     OutTextXY(70, 70, "Hello world!");
     SetTextStyle(1, 0, 20);
     OutTextXY(170, 50, "Кликните мышкой...");
-    int m = ReadMouseButton();
-    SetColor(clRed);
-    SetTextStyle(1, 0, 20);
-    if(m == 1) OutTextXY(150, 80, "Нажата левая кнопка");
-    else if(m == 2) OutTextXY(150, 80, "Нажата правая кнопка");
-    else if(m == 3) OutTextXY(150, 80, "Нажата средняя кнопка");
-    else OutTextXY(150, 80, "Нажата неизвестная кнопка");
+    for (auto i = 3; i; --i)
+    {
+        auto m = ReadMouseButton();
+        SetColor(clRed);
+        SetTextStyle(1, 0, 20);
+        if(m & 1) OutTextXY(150, 80, "Нажата левая кнопка");
+        if(m & 2) OutTextXY(150, 100, "Нажата правая кнопка");
+        if(m & 4) OutTextXY(150, 120, "Нажата средняя кнопка");
+        if(m & ~(1|2|4)) OutTextXY(150, 80, "Нажата неизвестная кнопка");
+    }
     SetTextStyle(2, 180, 30);
     OutTextXY(460, 550, "Hello world!");
     SetColor(0x999999);
С клавиатурой наверняка аналогично.

Вообще я хотел сделать стэк нажатых клавиш и кликов мыши, чтобы не терять те, которые не успел обработать во время Delay, например.
Очередь сообщений это палка о двух концах. Если в очереди накопились сообщения, вероятно, их обрабатывать уже поздно, если требуется реакция на действия пользователя "в реальном времени". Потому придумали "модель-вид-контроллер", сообщения, сигналы. Если библиотека разработана для детей, наверное, всё это слишком сложно и не нужно.

Оффлайн tema

  • alt linux team
  • ***
  • Сообщений: 2 073
Re: qtSimpleGraph
« Ответ #5 : 11.01.2021 00:34:30 »
Выглядит очень неплохо! А можно это не сюда, а в виде пуллреквеста на гитхабе, чтобы я просто внëс эти изменения?
Есть, правда, одна проблема. Большой код, который сейчас вычеркнут - он более подробный и его гораздо проще и с педагогической стороны более правильно разобрать с детьми. Сама библиотека задумана как второй этап изучения с детьми этой темы.
По сути, убрать EventMouseClicked можно было просто проверяя равенство переменной IDMouseButton и -1. Но я разделил эти два события совсем почему-то. И вот сейчас навскидку не могу вспомнить и объяснить что мне такого "гениального" пришло в голову, что я ввëл эти булевы переменные для мыши и клавы (дело было глубокой ночью и код сначала был без них. Я ввëл их нарочно. Это я точно помню, но не могу вспомнить зачем. Возможно, это в моей голове в этот момент зарождался очередной параграф методички по преподаванию именно этого момента детям не в связке, а, сначала, по-отдельности)
« Последнее редактирование: 11.01.2021 00:55:50 от tema »

Оффлайн trs

  • Участник
  • *
  • Сообщений: 287
Re: qtSimpleGraph
« Ответ #6 : 11.01.2021 12:37:37 »
Если флаг зачем-то добавляли, тогда вряд ли надо удалять (по крайней мере, сразу). Потом вспомните. Флаг эмулирует очередь из одного элемента (при произвольной глубине вместо него будет размер-счётчик, либо ненулевой std::deque<int>::size()). В моём варианте возможна "гонка", если значение сбросится таймером после проверки MouseClicked(). Патч привёл, что бы показать неясное место, потому он "сыроват".