Политика конфиденциальностиКонтактыО сайтеОтзывыGitHubDonate
© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

GameDev на Qt - Урок 1. Отслеживание перемещения мыши в QGraphicsScene

Qt, mouse, cursor, отслеживание, QGraphicsScene, GameDev

Все помнят игру Crimsonland ? Там нужно было валить монстров штабелями. Для перемещения по игровому полю мы использовали клавиши W, A, S, D, а для направления стрельбы курсор мыши , за которым производилось отслеживание. Так вот, сам по себе механизм работы этого самого отслеживания мыши предельно прост. Реализаций может быть множество, в зависимости от используемых инструментов в программировании, но если говорить об обычном QGraphicsScene , то позвольте продемонстрировать Вам мой вариант реализации подобного механизма.

Структура проекта

В этом проекте помимо основных файлов используется два дополнительных класса. Первый - это кастомизированный QGraphicsScene , который будет производить отслеживание положения курсора и передавать информацию о его положении, а второй - это главный герой, наш любимый Красный Треугольник , которым мы будем управлять с помощью клавиш W, A, S, D.

Структура проекта:

  • TargetMotion.pro - Профайл проекта;
  • widget.h - Заголовочный файл основного окна приложения;
  • widget.cpp - Файл исходных кодов основного окна приложения;
  • triangle.h - Заголовочный файл главного героя Красного Треугольника;
  • triangle.cpp - Файл исходных кодов главного героя Красного Треугольника;
  • customscene.h - Заголовочный файл кастомизированной графической сцены;
  • customscene.cpp - Файл исходных кодов кастомизированной графической сцены;
  • cursor.qrc - файл ресурсов, в котором содержится кастомизированный курсор мыши.

Пишем отслеживание курсора мыши

widget.ui

Файл формы главного окна приложения. В него лишь закидываем объект класса QGraphicsView и растягиваем его по всему окну.

customscene.h

Всё, что нужно сделать в данном заголовочном файле, это лишь объявить метод для отслеживания перемещения мыши mouseMoveEvent() и сигнал, в котором будут передаваться координаты положения мыши, не забывая отнаследовать класс от QGraphicsScene.

#ifndef CUSTOMSCENE_H
#define CUSTOMSCENE_H

#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>

class CustomScene : public QGraphicsScene
{
    Q_OBJECT
public:
    explicit CustomScene(QObject *parent = 0);
    ~CustomScene();

signals:
    // Сигнал для передачи координат положения курсора мыши
    void signalTargetCoordinate(QPointF point);

public slots:

private:
    // Функция, в которой производится отслеживание положения мыши
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
};

#endif // CUSTOMSCENE_H

customscene.cpp

Вы не поверите, но в файле исходных кодов Мы всего лишь вызываем сигнал с координатами в методе mouseMoveEvent.

#include "customscene.h"

CustomScene::CustomScene(QObject *parent) :
    QGraphicsScene()
{
    Q_UNUSED(parent);
}

CustomScene::~CustomScene()
{

}

void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    emit signalTargetCoordinate(event->scenePos());
}

triangle.h

А теперь объявим все объекты и функции, необходимые для правильной отрисовки нашего героя и реализации отслеживания курсора в игре. Для более полного представления о работе данного класса и его истоков рекомендую ознакомиться с циклом статей "Как написать игру на Qt" , который представлен в разделе Qt Уроки .

Примечание . Для обработки нажатий кнопок используются библиотеки WinAPI .

#ifndef TRIANGLE_H
#define TRIANGLE_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QPolygon>
#include <QTimer>

#include <windows.h>

class Triangle : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Triangle(QObject *parent = 0);
    ~Triangle();

signals:

public slots:
    // Слот для получения данных о положении курсора
    void slotTarget(QPointF point);

private:
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private slots:
    void slotGameTimer();   // Игровой слот

private:
    QTimer *gameTimer;      // Игровой таймер
    QPointF target;         // Положение курсора
};

#endif // TRIANGLE_H

triangle.cpp

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

#include "triangle.h"
#include <math.h>

static const double Pi = 3.14159265358979323846264338327950288419717;
static double TwoPi = 2.0 * Pi;

static qreal normalizeAngle(qreal angle)
{
    while (angle < 0)
        angle += TwoPi;
    while (angle > TwoPi)
        angle -= TwoPi;
    return angle;
}

Triangle::Triangle(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    setRotation(0);      // Устанавливаем исходный разворот треугольника
    gameTimer = new QTimer();   // Инициализируем игровой таймер
    // Подключаем сигнал от таймера и слоту обработки игрового таймера
    connect(gameTimer, &QTimer::timeout, this, &Triangle::slotGameTimer);
    gameTimer->start(10);   // Стартуем таймер
    target = QPointF(0,0);  // Устанавливаем изначальное положение курсора
}

Triangle::~Triangle()
{

}

QRectF Triangle::boundingRect() const
{
    return QRectF(-20,-30,40,60);
}

void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    /* Отрисовка треугольника
     * */
    QPolygon polygon;
    polygon << QPoint(0,-30) << QPoint(20,30) << QPoint(-20,30);
    painter->setBrush(Qt::red);
    painter->drawPolygon(polygon);

    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Triangle::slotTarget(QPointF point)
{
    // Определяем расстояние до цели
    target = point;
    QLineF lineToTarget(QPointF(0, 0), mapFromScene(target));
    // Угол поворота в направлении к цели
    qreal angleToTarget = ::acos(lineToTarget.dx() / lineToTarget.length());
    if (lineToTarget.dy() < 0)
        angleToTarget = TwoPi - angleToTarget;
    angleToTarget = normalizeAngle((Pi - angleToTarget) + Pi / 2);

    /* В Зависимости от того, слева или справа находится Цель от Героя,
     * устанавливаем направление поворота Героя в данном тике таймера
     * */
    if (angleToTarget >= 0 && angleToTarget < Pi) {
        // Rotate left
        setRotation(rotation() - angleToTarget * 180 /Pi);
    } else if (angleToTarget <= TwoPi && angleToTarget > Pi) {
        // Rotate right
        setRotation(rotation() + (angleToTarget - TwoPi )* (-180) /Pi);
    }
}

void Triangle::slotGameTimer()
{
    /* Перемещаем треугольник в зависимости от нажатых кнопок
     * */
    if(GetAsyncKeyState('A')){
        this->setX(this->x() - 2);
    }
    if(GetAsyncKeyState('D')){
        this->setX(this->x() + 2);
    }
    if(GetAsyncKeyState('W')){
        this->setY(this->y() - 2);
    }
    if(GetAsyncKeyState('S')){
        this->setY(this->y() + 2);
    }

    /* Проверка выхода за границы поля
     * Если объект выходит за заданные границы, то возвращаем его назад
     * */
    if(this->x() - 30 < 0){
        this->setX(30);         // слева
    }
    if(this->x() + 30 > 500){
        this->setX(500 - 30);   // справа
    }

    if(this->y() - 30 < 0){
        this->setY(30);         // сверху
    }
    if(this->y() + 30 > 500){
        this->setY(500 - 30);   // снизу
    }

    QLineF lineToTarget(QPointF(0, 0), mapFromScene(target));
    // Угол поворота в направлении к цели
    qreal angleToTarget = ::acos(lineToTarget.dx() / lineToTarget.length());
    if (lineToTarget.dy() < 0)
        angleToTarget = TwoPi - angleToTarget;
    angleToTarget = normalizeAngle((Pi - angleToTarget) + Pi / 2);

    /* В Зависимости от того, слева или справа находится Цель от Героя,
     * устанавливаем направление поворота Героя в данном тике таймера
     * */
    if (angleToTarget >= 0 && angleToTarget < Pi) {
        // Rotate left
        setRotation(rotation() - angleToTarget * 180 /Pi);
    } else if (angleToTarget <= TwoPi && angleToTarget > Pi) {
        // Rotate right
        setRotation(rotation() + (angleToTarget - TwoPi )* (-180) /Pi);
    }
}

widget.h

А теперь необходимо всё свести в игровом ядре, которое будет находится в классе главного окна приложения.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGraphicsScene>
#include <QGraphicsItem>

#include <triangle.h>
#include <customscene.h>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;
    CustomScene  *scene;    // Объявляем графическую сцену
    Triangle *triangle;     // Объявляем треугольник
};

#endif // WIDGET_H

widget.cpp

В данном файле объявляются и инициализируются все игровые объекты (графическая сцена и треугольник), а также используется паттерн проектирования типа Мост, через который передаётся сигнал от графической сцены к треугольнику.

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

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    // Устанавливаем параметры окна приложения
    this->resize(600,600);
    this->setFixedSize(600,600);

    ui->setupUi(this);
    scene   = new CustomScene();    // Инициализируем кастомизированную сцену

    ui->graphicsView->setScene(scene);  /// Устанавливаем графическую сцену в graphicsView
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);    /// Устанавливаем сглаживание
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по вертикали
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по горизонтали

    scene->setSceneRect(0,0,500,500);   // Устанавливаем размеры графической сцены

    // Создаем кастомизированный курсор из ресурсного файла
    QCursor cursor = QCursor(QPixmap(":/cursor/cursorTarget.png"));
    ui->graphicsView->setCursor(cursor);    // Устанавливаем курсор в QGraphicsView
    triangle = new Triangle();  // Инициализируем треугольник
    triangle->setPos(250,250);  // Устанавливаем стартовую позицию треугольника
    scene->addItem(triangle);   // Добавляем треугольник на графическую сцену

    /* Разрешаем отслеживание положение курсора мыши
     * без необходимости нажатия на кнопки мыши
     * Применяем это свойство именно для QGraphicsView,
     * в котором установлена графическая сцена
     * */
    ui->graphicsView->setMouseTracking(true);

    // Подключаем сигнал от графической сцены к слоту треугольника
    connect(scene, &CustomScene::signalTargetCoordinate, triangle, &Triangle::slotTarget);
}

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

Итог

В результате вы получите треугольник на графической сцене, который будет перемещаться по ней под воздействием клавиш W, A, S, D и всегда смотреть в сторону курсора мыши, если тот находится в пределах графической сцены.

Демонстрация данного примера приведена в видеоуроке по данной статье.

Видеоурок

r
10 февраля 2018 г. 15:12

А где можно найти полный код проекта (проектов)? У меня ошибки линковки типа ( LNK2019: ссылка на неразрешенный внешний символ "public: void __cdecl Triangle::slotTarget(class QPointF)" (?slotTarget@Triangle@@QEAAXVQPointF@@@Z) в функции "public: __cdecl Widget::Widget(class QWidget *)" ).  И может кто подскажет как поправить?

11 февраля 2018 г. 14:21

Вот в этой статье в конце есть полный проект.

r
11 февраля 2018 г. 15:45

спасибо

r
11 февраля 2018 г. 15:47

а если например я хочу сделать вместо треугольников - текстурки, я могу это сделать в этом виджете Qt? или надо брать что то другое?

11 февраля 2018 г. 16:22

Для отрисовки используется объект класса QPainter  методе paint у треугольника. А этот класс QPainter имеет метод drawPixmap(), который может отрисовывать изображение из png файла например. Поэтому да, можете лишь переписать метод paint, и отрисовывать текстуры.

r
11 февраля 2018 г. 16:28

еще такой вопрос. у меня Qt ругается на GetAsyncKeyState (ошибка линковки). Надо либу какую то подключить? 2) а есть такая функция н кросс платформенная (зачем в таком достаточно высокоуровневом фреймворке использовать winApi?)?

11 февраля 2018 г. 16:35

Для MSVC пропишите в pro файле проекта следующие строчки

win32-msvc*{
    LIBS += -luser32
}
Видите ли, фреймворк может и достаточно высокоуровневый, но некоторый особенности работы в нём не реализованы в кросплатформенном варианте.
Например, нет тех же самых глобальных хоткеев . Я сам занимался реализацией подобного функционала для одного своего проекта.
 
Поэтому и проверка статуса клавиш тоже из этого разряда. А если говорить конкретнее, то проблема в том, что состояния клавиш проходят через цепочку событий
11 февраля 2018 г. 16:39

цепочку событий Qt приложения. Что влёчет к значительному усложнению кода, да ещё и может помешать фокусировка на некоторых виджетах, то есть события фокуса ещё вмешиваются. Здесь фокус должен сохраняться на виджете, в котором происходит действие, чтобы корректно отрабатывать нажатия клавиш. В общем много головной боли сразу появляется. Обработка события клавиш в Qt немного неподходит для реализации игровой логики на клавиатуре, это как раз один из тех моментов, когда действительно проще навелосипедить своё... хотя я противник велосипедов, но Qt не даёт нужного функционала в достаточной мере.

r
11 февраля 2018 г. 16:50

я собираю под win64.    LIBS += -luser32 и  LIBS += -luser64 не помогает

12 февраля 2018 г. 6:22

Вы вообще что-то своё уже пишите, или как? Я скачал проект, запустил его на работе на Win64 и он работает.

А так по факту заголовочник нужен
#include <windows.h>
r
12 февраля 2018 г. 17:39

Да нет. Чет у меня с qt только проблемы. Ваш проект так в qt не смог собрать (из за GetAsyncKeyState). Собрал его в visual studio, но там почему то пришлось в ручную кидать .dll в каталог (хотя путь добавлял) (может тут что изменить см скрин https://yadi.sk/i/-D9CsBhh3SL2eQ ).

r
12 февраля 2018 г. 18:01

Еще пару вопросов по code-style

1)override в qt не используется?
2)почему 0 а не nullptr ?
3)макрос Q_UNUSED. Почему нельзя просто не давать переменным имя и тд?
4)Зачем объявлять что то если там пустое тело?  (2)
5)Зачем прописывать вызов конструктора по умолчанию? (2)
6)Почему иногда не чистится динамическая память? это ошибка? не лучше ли использовать std::unique_ptr указатели вместо обычных?
7)почему нужно объявлять именно указатели на объекты и вызывать new в конструкторе, а не просто делать объекты членами класса (а не их указатели)?
8) такие штуки как public slots: , где  slots макрос который раскрывается в ничего. Для чего нужны? (просто для оформления)?
9) такие штуки как emit. Это пустые макросы. Они для оформления, или код сначала прогоняется в компиляторе qt который понимает эти "ключевые слова" ?

12 февраля 2018 г. 21:21

Честно говоря... не знаю... Я не работаю с Visual Studio вообще. В основном Qt Creator, да иногда с CLion. Больше походит на то, что у вас некорректно установлены пути к библиотекам Qt в операционной системе. Либо сама Visual Studio криво встала.

12 февраля 2018 г. 21:56

По code-style

Признаюсь честно, сам находился в плавающем состоянии, когда писал ранние статьи, как раз чтобы всё уложить в голове по полочкам, поэтому многие ваши замечания весьма к месту. Но сейчас могу более адекватно и развёрнуто Вам ответить на ваши вопросы.
  1. override в Qt используется, но они в своей странной манере в очередной раз всё переопределили своими макросами, хотя наверняка были ещё какие-то причины, которые сейчас можно считать морально устаревшими. По факту у них есть макрос Q_OVERRIDE, но я всегда пишу override (до кучи ещё и virtual добавляю), а в использовании Q_OVERRIDE не вижу смысла.
  2. На момент изучения всей этой кухни Qt не особо обратил внимание на этот момент, да и не работал плотно в рамках стандарта C++11, а так да, лучше использовать nullptr . Сейчас всегда его использую.
  3. Это уже вопрос вкусовщины. Я придерживался рамок code-style Qt, а по факту можно и не писать имя переменной, разницы принципиально никакой не будет. Q_UNUSED всё равно приводит переменную к void и типо она используется.
  4. Относительно конструкторов и деструкторов - это привычка, писать их реализацию.
  5. Там лучше передать parent`а в конструктор базового класса, мой косяк.
  6. Насчёт памяти в Qt такая ситуация, у всех классов, наследованных от Qt желательно передавать parent. Тогда при уничтожении, parent будет прибирать за собой всех потомков, поэтому и не потребуется использовать умные указатели. В этом примере некоторые недочёты имеются, нужно передавать парента при создании объекта, чего я не везде сделал, тогда утечек не будет.
  7. Лучше, как вы и сказали объявлять объекты членами класса, там например QTimer можно объявить  на стеке. Не помню, только с графической сценой как лучше будет, точно помню есть проблемы с объектами QGraphicsItem , их всегда приходится объявлять в куче, на стеке память не выделить. Работать просто не будет. С графической сценой кажется тоже какие-то проблемы в отображении были, не помню уже.
  8. Объявление в качестве slots нужно было для формирования moc файлов, когда использовался старый синтаксис сигналов и слотов на основе макросов. Скомпилироваться-то скомпилируется, если слот не объявлен в секции слотов, но работать не будет... А вот в случае с новым синтаксисом на основе указателей на методы уже да, не обязательно писать slots и т.д. Но по мне здесь лучше оставить их, это уже вопрос код стайла и разделения по секциями методов, которые должны использоваться как слоты, а какие нет.
  9. а вот emit - это действительно пустышки, я пытался найти адекватное объяснение, для чего они, но кроме того, что это синтаксический сахар, который призван указать вызов именно метода сигнала в коде, ничего не нашёл. Обычно всегда пишу их, чтобы глазу было за что зацепиться. Возможно раньше, в более ранних версиях Qt это было обязательным, сейчас точно нет. Но я застал только Qt 4.8, да и то только вскользь.
r
13 февраля 2018 г. 16:35

Спасибо за ответы. Еще хотел спросить. Вы занимались программированием сетевых игр? вот например если у нас 2 клиента (у каждого свой треугольник). Как например синхронизируется картинка, сколько раз в секунду передаются действия? просто не оч понимаю как удается избегать задержек и делать плавную картинку

r
13 февраля 2018 г. 20:24

А и по библиотеке. Зачем у qt своя библиотека вещей которые есть в в stl, boost и тд. Например зачем использовать всякие вектора Qt и тд когда они есть в stl? Или это зачем то нужно?

13 февраля 2018 г. 20:38

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


По факту синхронизация изображения должна соответствовать как минимум FPS, в идеале не ниже 60 раз в секунду, лучше больше. Но для очень динамичных игр используется не только передача данных о положении объектов, но и методологии предсказания будущего положения игроков и объектов в самой игре без получения данных от сервера или другого игрока. Именно поэтому иногда возникают лаги, когда вашего игрока перекидывает в другое место карты. Просто предсказание сработало неправильно, а при очередном обновлении данных от сервера игра скорректировала положения игрока на карте.  Это очень большая и обширная тема... к сожалению я тут профан.

Моё основное направление сейчас - это программное обеспечение для расчётов нагрузок строительных конструкций и зданий. В основном модели данных и взаимодействие всех компонентов системы. И т.д.
13 февраля 2018 г. 20:48

Ммм... здесь за версту отдаёт желанием написать всё своё. Кстати, голос разума у них всё-таки проснулся в Qt 5. Например, для сортировки там используется и рекомендуется уже std::sort , вместо qSort, который они пометили как deprecated. Что касается контейнеров, то у контейнеров Qt есть кое-какие удобные методы. Но последнее время я перехожу на контейнеры stl. Они гораздо функциональнее. Что касается boost, то сигналы и слоты, которые есть в boost, как говорят в интернетах, слизали именно с Qt. Так что все понемножку друг у друга заимствуют.



r
14 февраля 2018 г. 17:35

я переопределил paint треугольника. сделал рисование танчика и его пушки.

painter->drawPixmap(-30, -50, *spriteImage, 40, 0, 60, 100);
painter->drawPixmap(-20, -50, *spriteImage, 0, 0, 40, 100);
но текстура пушки белым фоном закрашивает часть танка (см скрины https://yadi.sk/d/QKmAHw8e3SL5A4 ). Как это исправить?
r
14 февраля 2018 г. 17:57

разобрался. заменил белый фон на альфаканал.  теперь другой вопрос. вот  Pixmap пушки я хочу поворачивать вокруг своей оси. можно это сделать както через setRotation например? (тоесть нарисовал корпус, повернул обьект, нарисовал пушку)

r
14 февраля 2018 г. 19:32

Фух и с этим разобрался. Теперь такой вопрос, а можно ли как-то по лучше обрабатывать столкновения обьектов, и чтоб к стене например можно было подъехать в плотную, и при этом не вьехать в ней повернувшись на месте?

14 февраля 2018 г. 21:28

Здесь уже нужно обрабатывать очертания танка и не давать возможность ему разворачиваться, если есть риск въехать в стену.

Но для этого нужно немного изменить логику обработки коллизий. Дело в том, что в данном варианте коллизии обрабатываются по факту, когда коллизии уже произошли.
А вот следующим шагом можете начать обрабатывать коллизии с предсказанием. То есть условно взять будущее положение танка и проверить на коллизии. У графической сцены есть метод items(), в этот метод можно передать объект QPolygonF, который можете описывать очертания танка в его будущем положении на карте. Если будет возвращён хотя бы один объект, то моно считать, что коллизия имеет место быть, а значит танк нельзя подвинуть или повернуть, а тогда просто не выполняете движение танка в заданном положении.
r
16 февраля 2018 г. 16:22

А не подскажите как сделать плавность анимации или как то так. например танк (прямоугольник) едет вверх и вертикален. Потом игрок нажимает клавишу влево и он должен уже ехать вертикально. Можно конечно плавно поворачивать текстуру но я думаю можно сделать лучше. Просто играл в танчики где корпус и пушка могут вращатся и ехать мгновенно на любой градус, и при этом там не было видимого резкого скачка (может это какоето сглаживание?)

16 февраля 2018 г. 20:46

Если просто сменить угол поворота или направление, то скачок всегда будет резким. Если хотите добавить некоторую плавность в поворот, то нужно делать поворот за несколько отсчётов игрового таймера, чтобы это было достаточно быстро, но при этом добавило некоторую плавность.


Нечто подобное я сделал вот в этой статье . Посмотрите следующий метод void Spider::slotGameTimer().

И ещё, у меня просьба. Создавайте, пожалуйста, новые вопросы на форуме . Там можно при создании вопроса указать статью, к которой имеет отношение данный вопрос. Так будет лучше для развития ресурса. Спасибо.
a
7 мая 2018 г. 5:45

forgetting otnasledovat class from QGraphicsScene :D

7 мая 2018 г. 10:09

Ну да, поленился внимательно посмотреть перевод после Google Translate :D

Спасибо, поправил

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
ДД
13 декабря 2018 г. 16:24
Дмитрий Дубовик

C++ - Тест 005. Структуры и Классы

  • Результат:66баллов,
  • Очки рейтинга-1
13 декабря 2018 г. 16:04
Metelev

Qt - Тест 001. Сигналы и слоты

  • Результат:47баллов,
  • Очки рейтинга-6
YC
12 декабря 2018 г. 18:49
Yaroslav Chernetskyi

Qt - Тест 001. Сигналы и слоты

  • Результат:31баллов,
  • Очки рейтинга-10
Последние комментарии
V
15 декабря 2018 г. 2:06
Vlad15007

Спасибо большое!Очень помогли!
11 декабря 2018 г. 21:01
Евгений Легоцкой

Не знаю, какой-там конкретно эффект и если честно не хочется fl studio ради того, чтобы посмотреть устанавливать, но из того, что увидел в интернете. Предполагаю, что то, что вы хотите с...
V
11 декабря 2018 г. 19:25
Vlad15007

Подскажите пожалуйста ( я новичок совсем)Можно ли организовать спрайт без этого окошка (как в fl studio fruity dance)?
11 декабря 2018 г. 15:06
Евгений Легоцкой

Что интересно, если написать так from <application_name>.<module_name> import <filename> ,то PyCharm сносит крышу, если разрабатываешь в рамках проекта приложение, ко...
11 декабря 2018 г. 14:52
Илья Чичак

Тут мне тоже есть что сказать=) Сами разрабы советуют импортировать следующим образом: from <application_name> import <module_name> Стоит избегать from . import &l...;
Сейчас обсуждают на форуме
17 декабря 2018 г. 17:55
Евгений Легоцкой

Просчитывать перекрытие точек и не отрисовывать те точки, которые перекрываются другими. У вас их просто слишком много, нужно смотреть, какие можно не отрисовывать без потери информативн...
R
16 декабря 2018 г. 14:41
RED_Spider

перевірено все працює http://doc.qt.io/qt-5/appicon.html Setting the Application Icon on Windows First, create an ICO format bitmap file that contains the icon image. This ca...
16 декабря 2018 г. 11:26
Евгений Легоцкой

Только статические методы и участники класса можно вызывать подобным образом Cell::sum У вас же они нестатические, чтобы их вызывать, нужно иметь объект Cell. Вы его, конечно, со...
q
15 декабря 2018 г. 23:02
qdu10719

Понял, спасибо большое
БГ
14 декабря 2018 г. 17:44
Булат Гиниятов

Большое всем спасибо за помощь! Использую вариант с QList.
Присоединяйтесь к нам в социальных сетях

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы