Evgenii Legotckoi
Evgenii Legotckoi2. Juli 2016 10:13

Qt/C++ - Lektion 052. Anpassung Qt Audioplayer im Stil von AIMP

Artikel dieses Zyklus:

Im Artikel über die Arbeit mit dem Audioplayer in Qt haben wir uns mit dem Abspielen von Audiospuren und dem Wechseln zwischen ihnen in einer Wiedergabeliste vertraut gemacht.

Wie wäre es, das Erscheinungsbild des Players so anzupassen, dass es beispielsweise wie AIMP aussieht? Schauen wir uns nur zum Vergleich das ursprüngliche AIMP und das Erscheinungsbild des Players nach der Anpassung an.


Das Hauptproblem bei dieser Anpassung von Qt-Anwendungen besteht darin, dass Qt nicht über die Möglichkeit verfügt, den Rahmen des Anwendungsfensters anzupassen. Das heißt, im Fall von Windows ist es notwendig, WinAPI zu verwenden, um das Fenster zu dekorieren, und im Fall von Unix- und Linux-Systemen ist es notwendig, die entsprechenden Window-Decorator-APIs zu verwenden.

Das einzige, was Qt tun kann, ist, die Fensterränder vollständig zu deaktivieren. Dann müssen Sie die Fensterdekoration vollständig mit Qt schreiben, ohne die Fähigkeiten des Betriebssystems zu nutzen, die Logik für die Schaltflächen schreiben, um das Fenster zu minimieren und zu maximieren, sowie die Logik zum Verschieben und Ändern der Größe des Anwendungsfensters. Zeichnen Sie dementsprechend alle Stile von Schnittstellenelementen mit dem QSS StyleSheet-Mechanismus. Eine alternative Designoption ist QPalette, aber Stile werden im Gegensatz zur Verwendung von QSS Stylesheet nicht immer korrekt verarbeitet.

Anwendungsfensterränder deaktivieren

Damit die Anwendungsschnittstelle korrekt verarbeitet werden kann, benötigen wir:

  • Fensterrahmen deaktivieren;
  • Machen Sie das Haupt-Widget des Fensters transparent, in dem sich die gesamte Oberfläche befindet;
  • und platzieren Sie die Elemente der Benutzeroberfläche selbst in einem anderen Widget, das sich innerhalb des Haupt-Widgets befindet und gleichzeitig nicht transparent ist;
  • Sie müssen auch einen Schatten um das Widget mit einer Schnittstelle erstellen, um den Schatten aus dem Anwendungsfenster zu emulieren, wie es für gewöhnliche Fenster, einschließlich des AIMP-Fensters, gemacht wird.

Bevor die Fensterränder deaktiviert und das Haupt-Widget in den transparenten Modus versetzt wurden, wurden einige Änderungen an der Benutzeroberfläche selbst im Grafikdesigner vorgenommen.

Wie Sie dem Elementbaum entnehmen können, gibt es ein Haupt-Widget, das transparent sein sollte, sowie ein Widget mit einer grafischen Oberfläche. Der Bereich, der zwischen den Rändern zweier rechteckiger roter Auswahlen eingeschlossen ist, ist der sichtbare Teil des Haupt-Widgets. Es enthält den Schatten des Anwendungsfensters sowie den Bereich, der zum Ändern der Größe des Anwendungsfensters verwendet wird.

Das Qt::FramelessWindowHint -Flag muss gesetzt werden, um Fensterrahmen zu deaktivieren. Um den Hintergrund des Widgets in den vollständig transparenten Modus zu versetzen, legen Sie das Attribut Qt::WA_TranslucentBackground fest.

Die Installation des Schattens muss nicht mehr auf dem Haupt-Widget selbst erfolgen, sondern auf dem Widget, das die Anwendungsoberfläche enthält. Um einen Schatteneffekt zu erzeugen, wird ein Objekt der Klasse QGraphicsFropShadowEffect. verwendet.

All dies erledigen wir im Klassenkonstruktor Widget , der für das Anwendungsfenster verantwortlich ist.

/// Настройка UI
this->setWindowFlags(Qt::FramelessWindowHint);      // Отключаем оформление окна
this->setAttribute(Qt::WA_TranslucentBackground);   // Делаем фон главного виджета прозрачным
this->setStyleSheet(StyleHelper::getWindowStyleSheet());    // Устанавливаем стиль виджета

// Создаём эффект тени
QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(this);
shadowEffect->setBlurRadius(9); // Устанавливаем радиус размытия
shadowEffect->setOffset(0);     // Устанавливаем смещение тени
ui->widgetInterface->setGraphicsEffect(shadowEffect);   // Устанавливаем эффект тени на окно
ui->widgetInterface->layout()->setMargin(0);            // Устанавливаем размер полей
ui->widgetInterface->layout()->setSpacing(0);           // Устанавливаем размер пространства между элементами в размещении виджета

QSS-Stylesheet

Wie Sie bereits bemerkt haben, wird im obigen Codeabschnitt die Klasse StyleHelper verwendet, die die statische Methode getWindowStyleSheet() aufruft. Diese Klasse ist eine Hilfsklasse und gibt einen QString zurück, der den Stil für die Gestaltung des Schnittstellen-Widgets beschreibt. Diese Methoden setzen auch Schaltflächensymbole aus Ressourcendateien, einige dieser Symbole werden unten gezeigt.

QSS-Stile werden nach dem Prinzip von CSS-Stilen im Weblayout implementiert. Sie sind für genau die gleichen Parameter verantwortlich. Zum Beispiel Padding, Margin etc.

Die Klasse StyleHelper mit folgendem Inhalt wird verwendet, um die Fensterdekoration für diese Anwendung zu implementieren.

stylehelper.h

Ich mache Sie darauf aufmerksam, dass die Klasse zwei Methoden verwendet, mit Stilen, die unter bestimmten Bedingungen auf dasselbe Element (die Schaltfläche zum Maximieren / Normalisieren der Größe des Anwendungsfensters) angewendet werden. Dies sind die Methoden getMaximizeStyleSheet() und getRestoreStyleSheet().

#ifndef STYLEHELPER_H
#define STYLEHELPER_H

#include <QString>

class StyleHelper
{
public:
    static QString getWindowStyleSheet();
    static QString getLabelStyleSheet();
    static QString getCloseStyleSheet();
    static QString getMaximizeStyleSheet();
    static QString getRestoreStyleSheet();
    static QString getMinimizeStyleSheet();
    static QString getNextStyleSheet();
    static QString getPreviousStyleSheet();
    static QString getStopStyleSheet();
    static QString getPlayStyleSheet();
    static QString getPauseStyleSheet();
    static QString getMenuStyleSheet();
    static QString getTableViewStyleSheet();
};

#endif // STYLEHELPER_H

stylehelper.cpp

Wie Sie sehen, beschreiben die Klassenmethoden den Stil der gesamten Anwendungsoberfläche sowie Stile für die sogenannten Pseudoklassen, die für den Zustand des Objekts verantwortlich sind, wenn darauf geklickt wird oder wenn der Mauszeiger darüber liegt dieses Objekt. Für diese Zustände erfolgt auch die Verbindung verschiedener Icons, wie für die Schaltflächen in der Anwendung.

#include "stylehelper.h"

QString StyleHelper::getWindowStyleSheet()
{
    return "QWidget { "
           "background-color: #454545; "
           "border: 1px solid black; "
           "}";
}

QString StyleHelper::getLabelStyleSheet()
{
    return "QLabel { "
           "color: #8f8f8f; "
           "border: none; "
           "margin: 6px; "
           "}";
}

QString StyleHelper::getCloseStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/close-orange.png);"
           "background-color: #292929; "
           "icon-size: 12px;"
           "padding-left: 10px;"
           "padding-right: 10px;"
           "padding-top: 5px;"
           "padding-bottom: 5px;"
           "border: 1px solid #292929; "
           "}"
           "QToolButton:hover {"
           "image: url(:/buttons/close.png); "
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/close.png);"
           "background-color: #de8e37; "
           "}";
}

QString StyleHelper::getMaximizeStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/window-maximize-gray.png);"
           "background-color: #292929;"
           "icon-size: 12px;"
           "padding-left: 10px;"
           "padding-right: 10px;"
           "padding-top: 5px;"
           "padding-bottom: 5px;"
           "border: 1px solid #292929; "
           "}"
           "QToolButton:hover {"
           "image: url(:/buttons/window-maximize.png); "
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/window-maximize.png);"
           "background-color: #de8e37; "
           "}";
}

QString StyleHelper::getRestoreStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/window-restore-gray.png);"
           "background-color: #292929;"
           "icon-size: 12px;"
           "padding-left: 10px;"
           "padding-right: 10px;"
           "padding-top: 5px;"
           "padding-bottom: 5px;"
           "border: 1px solid #292929; "
           "}"
           "QToolButton:hover {"
           "image: url(:/buttons/window-restore.png); "
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/window-restore.png);"
           "background-color: #de8e37; "
           "}";
}

QString StyleHelper::getMinimizeStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/window-minimize-gray.png);"
           "background-color: #292929;"
           "icon-size: 12px;"
           "padding-left: 10px;"
           "padding-right: 10px;"
           "padding-top: 5px;"
           "padding-bottom: 5px;"
           "border: 1px solid #292929; "
           "}"
           "QToolButton:hover { "
           "image: url(:/buttons/window-minimize.png); "
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/window-minimize.png);"
           "background-color: #de8e37; "
           "}";
}

QString StyleHelper::getNextStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/skip-next.png);"
           "icon-size: 24px;"
           "padding: 6px;"
           "margin: 6px;"
           "border: none;"
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/skip-next-orange.png)"
           "}";
}

QString StyleHelper::getPreviousStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/skip-previous.png);"
           "icon-size: 24px;"
           "padding: 6px;"
           "margin: 6px;"
           "border: none;"
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/skip-previous-orange.png)"
           "}";
}

QString StyleHelper::getStopStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/stop.png);"
           "icon-size: 24px;"
           "padding: 6px;"
           "margin: 6px;"
           "border: none;"
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/stop-orange.png)"
           "}";
}

QString StyleHelper::getPlayStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/play.png);"
           "icon-size: 48px;"
           "padding: 6px;"
           "margin: 6px;"
           "border: none;"
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/play-orange.png)"
           "}";
}

QString StyleHelper::getPauseStyleSheet()
{
    return "QToolButton { "
           "image: url(:/buttons/pause.png);"
           "icon-size: 24px;"
           "padding: 6px;"
           "margin: 6px;"
           "border: none;"
           "}"
           "QToolButton:pressed { "
           "image: url(:/buttons/pause-orange.png)"
           "}";
}

QString StyleHelper::getMenuStyleSheet()
{
    return "QToolButton { "
           "color: #8f8f8f;"
           "background-color: #292929;"
           "icon-size: 12px;"
           "padding-left: 10px;"
           "padding-right: 10px;"
           "padding-top: 5px;"
           "padding-bottom: 5px;"
           "border: 1px solid #292929; "
           "}"
           "QToolButton:hover {"
           "color: white;"
           "}"
           "QToolButton:pressed { "
           "color: white; "
           "background-color: #de8e37; "
           "}";
}

QString StyleHelper::getTableViewStyleSheet()
{
    return "QTableView { "
           "background-color: white; "
           "color: black; "
           "border: 1px solid #e2e2de;"
           "}"
           "QTableView::item:selected {"
           "background-color: #de8e37;"
           "}"
           "QHeaderView::section:horizintal {"
           "background-color: white;"
           "border-style: none;"
           "color: black; "
           "border: 1px solid #e2e2de; "
           "padding: 6px; "
           "}";
}

Größe und Position des Anwendungsfensters ändern

Da wir das Framing des Anwendungsfensters deaktiviert haben, fällt nun die Umsetzung dieser Aufgaben auf unsere Schultern.

Widget.h

Werfen wir einen Blick auf die Header-Datei des Widgets, um zu verstehen, was wir zur Implementierung dieser Funktionalität benötigen.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QStandardItemModel>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QMouseEvent>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT
    // Свойство с точкой предыдущей позиции мыши
    // Относительно данной точки идёт пересчёт позиции окна 
    // Или размеров окна. При этом свойство устанавливается при нажатии мыши
    // по окну и в ряде иных случаев
    Q_PROPERTY(QPoint previousPosition READ previousPosition WRITE setPreviousPosition NOTIFY previousPositionChanged)

    // тип клика мыши, при перемещении курсора по этому типу будем определять
    // что именно нужно сделать, перенести окно, или изменить его размер с одной из сторон
    enum MouseType {
        None = 0,
        Top,
        Bottom,
        Left,
        Right,
        Move
    };

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

public slots:
    void setPreviousPosition(QPoint previousPosition);

signals:
    void previousPositionChanged(QPoint previousPosition);

private slots:
    void on_btn_add_clicked();

protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

private:
    Ui::Widget *ui;
    QStandardItemModel  *m_playListModel;
    QMediaPlayer        *m_player;
    QMediaPlaylist      *m_playlist;

    // Переменная, от которой будем отталкиваться при работе с перемещением и изменением размера окна
    MouseType m_leftMouseButtonPressed;
    QPoint m_previousPosition;

    MouseType checkResizableField(QMouseEvent *event);
};

#endif // WIDGET_H

Widget.cpp

Um die Bewegung und Größenänderung des Anwendungsfensters zu implementieren, müssen Sie genau nachverfolgen, wo der Klick erfolgt ist. Wenn wir in ein Widget mit einer Benutzeroberfläche geklickt haben (wo es jedoch keine Steuerelemente gibt, die Klickereignisse abfangen, wie z. B. Schaltflächen), haben wir die Möglichkeit, das Anwendungsfenster zu verschieben. Wenn Sie zum Ändern der Größe auf einen der vier Bereiche geklickt haben, ändern wir die Größe entsprechend.

In der folgenden Abbildung sind die Bereiche zum Ändern der Größe rot dargestellt, und der Bereich zum Verschieben des Anwendungsfensters ist blau hervorgehoben.

Und jetzt beschäftigen wir uns mit dem Code, alle Momente darin sind kommentiert.

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QDir>
#include <QGraphicsDropShadowEffect>

#include "stylehelper.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget),
    m_leftMouseButtonPressed(None)
{
    ui->setupUi(this);
    /// Настройка UI
    this->setWindowFlags(Qt::FramelessWindowHint);      // Отключаем оформление окна
    this->setAttribute(Qt::WA_TranslucentBackground);   // Делаем фон главного виджета прозрачным
    this->setStyleSheet(StyleHelper::getWindowStyleSheet());    // Устанавливаем стиль виджета
    this->setMouseTracking(true);   // Включаем отслеживание курсора без нажатых кнопокы

    // Создаём эффект тени
    QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(this);
    shadowEffect->setBlurRadius(9); // Устанавливаем радиус размытия
    shadowEffect->setOffset(0);     // Устанавливаем смещение тени
    ui->widgetInterface->setGraphicsEffect(shadowEffect);   // Устанавливаем эффект тени на окно
    ui->widgetInterface->layout()->setMargin(0);            // Устанавливаем размер полей
    ui->widgetInterface->layout()->setSpacing(0);
    ui->label->setText("AIMP Fake Player");
    ui->label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);

    // Установка стилей для всех элементов
    ui->currentTrack->setStyleSheet(StyleHelper::getLabelStyleSheet());
    ui->label->setStyleSheet(StyleHelper::getLabelStyleSheet());
    ui->btn_close->setStyleSheet(StyleHelper::getCloseStyleSheet());
    ui->btn_maximize->setStyleSheet(StyleHelper::getMaximizeStyleSheet());
    ui->btn_minimize->setStyleSheet(StyleHelper::getMinimizeStyleSheet());
    ui->btn_next->setStyleSheet(StyleHelper::getNextStyleSheet());
    ui->btn_previous->setStyleSheet(StyleHelper::getPreviousStyleSheet());
    ui->btn_stop->setStyleSheet(StyleHelper::getStopStyleSheet());
    ui->btn_play->setStyleSheet(StyleHelper::getPlayStyleSheet());
    ui->btn_pause->setStyleSheet(StyleHelper::getPauseStyleSheet());
    ui->btn_add->setStyleSheet(StyleHelper::getMenuStyleSheet());
    ui->playlistView->setStyleSheet(StyleHelper::getTableViewStyleSheet());
    ui->btn_add->setText(tr("Добавить"));
    ui->btn_next->setCursor(Qt::PointingHandCursor);
    ui->btn_previous->setCursor(Qt::PointingHandCursor);
    ui->btn_stop->setCursor(Qt::PointingHandCursor);
    ui->btn_play->setCursor(Qt::PointingHandCursor);
    ui->btn_pause->setCursor(Qt::PointingHandCursor);

    ui->horizontalLayout->setSpacing(6);
    ///
    /* Код из предыдущей статьи */

    /// коннекты для кнопок сворачивания/максимизации/минимизации/закрытия
    // Сворачивание окна приложения в панель задач
    connect(ui->btn_minimize, &QToolButton::clicked, this, &QWidget::showMinimized);
    connect(ui->btn_maximize, &QToolButton::clicked, [this](){
        // При нажатии на кнопку максимизации/нормализации окна
        // Делаем проверку на то, в каком состоянии находится окно и переключаем его режим
        if (this->isMaximized()) {
            // Заметьте, каждый раз устанавливаем новый стиль в эту кнопку
            ui->btn_maximize->setStyleSheet(StyleHelper::getMaximizeStyleSheet());
            this->layout()->setMargin(9);
            this->showNormal();
        } else {
            ui->btn_maximize->setStyleSheet(StyleHelper::getRestoreStyleSheet());
            this->layout()->setMargin(0);
            this->showMaximized();
        }
    });
    // Закрытие окна приложения
    connect(ui->btn_close, &QToolButton::clicked, this, &QWidget::close);
    /* Код из предыдущей статьи */
}

Widget::~Widget()
{
    delete ui;
    delete m_playListModel;
    delete m_playlist;
    delete m_player;
}

QPoint Widget::previousPosition() const
{
    return m_previousPosition;
}

void Widget::setPreviousPosition(QPoint previousPosition)
{
    if (m_previousPosition == previousPosition)
        return;

    m_previousPosition = previousPosition;
    emit previousPositionChanged(previousPosition);
}

void Widget::on_btn_add_clicked()
{
    /* Код из предыдущего урока */
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    // При клике левой кнопкой мыши
    if (event->button() == Qt::LeftButton ) {
        // Определяем, в какой области произошёл клик
        m_leftMouseButtonPressed = checkResizableField(event);
        setPreviousPosition(event->pos()); // и устанавливаем позицию клика
    }
    return QWidget::mousePressEvent(event);
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    // При отпускании левой кнопки мыши сбрасываем состояние клика
    if (event->button() == Qt::LeftButton) {
        m_leftMouseButtonPressed = None;
    }
    return QWidget::mouseReleaseEvent(event);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    // При перемещении мыши, проверяем статус нажатия левой кнопки мыши
    switch (m_leftMouseButtonPressed) {
    case Move: {
        // При этом проверяем, не максимизировано ли окно
        if (isMaximized()) {
            // При перемещении из максимизированного состояния
            // Необходимо вернуть окно в нормальное состояние и установить стили кнопки
            // А также путём нехитрых вычислений пересчитать позицию окна, 
            // чтобы оно оказалось под курсором
            ui->btn_maximize->setStyleSheet(StyleHelper::getMaximizeStyleSheet());
            this->layout()->setMargin(9);
            auto part = event->screenPos().x() / width();
            this->showNormal();
            auto offsetX = width() * part;
            setGeometry(event->screenPos().x() - offsetX, 0, width(), height());
            setPreviousPosition(QPoint(offsetX, event->y()));
        } else {
            // Если окно не максимизировано, то просто перемещаем его относительно
            // последней запомненной позиции, пока не отпустим кнопку мыши
            auto dx = event->x() - m_previousPosition.x();
            auto dy = event->y() - m_previousPosition.y();
            setGeometry(x() + dx, y() + dy, width(), height());
        }
        break;
    }
    case Top: {
        // Для изменения размеров также проверяем на максимизацию
        // поскольку мы же не можем изменить размеры у максимизированного окна
        if (!isMaximized()) {
            auto dy = event->y() - m_previousPosition.y();
            setGeometry(x(), y() + dy, width(), height() - dy);
        }
        break;
    }
    case Bottom: {
        if (!isMaximized()) {
            auto dy = event->y() - m_previousPosition.y();
            setGeometry(x(), y(), width(), height() + dy);
            setPreviousPosition(event->pos());
        }
        break;
    }
    case Left: {
        if (!isMaximized()) {
            auto dx = event->x() - m_previousPosition.x();
            setGeometry(x() + dx, y(), width() - dx, height());
        }
        break;
    }
    case Right: {
        if (!isMaximized()) {
            auto dx = event->x() - m_previousPosition.x();
            setGeometry(x(), y(), width() + dx, height());
            setPreviousPosition(event->pos());
        }
        break;
    }
    default:
        // Если курсор перемещается по окну без зажатой кнопки,
        // то просто отслеживаем в какой области он находится
        // и изменяем его курсор
        checkResizableField(event);
        break;
    }
    return QWidget::mouseMoveEvent(event);
}

Widget::MouseType Widget::checkResizableField(QMouseEvent *event)
{
    QPointF position = event->screenPos();  // Определяем позицию курсора на экране
    qreal x = this->x();                    // координаты окна приложения, ...
    qreal y = this->y();                    // ... то есть координату левого верхнего угла окна
    qreal width = this->width();            // А также ширину ...
    qreal height = this->height();          // ... и высоту окна

    // Определяем области, в которых может находиться курсор мыши
    // По ним будет определён статус клика
    QRectF rectTop(x + 9, y, width - 18, 7);
    QRectF rectBottom(x + 9, y + height - 7, width - 18, 7);
    QRectF rectLeft(x, y + 9, 7, height - 18);
    QRectF rectRight(x + width - 7, y + 9, 7, height - 18);
    QRectF rectInterface(x + 9, y + 9, width - 18, height - 18);

    // И в зависимости от области, в которой находится курсор
    // устанавливаем внешний вид курсора и возвращаем его статус
    if (rectTop.contains(position)) {
        setCursor(Qt::SizeVerCursor);
        return Top;
    } else if (rectBottom.contains(position)) {
        setCursor(Qt::SizeVerCursor);
        return Bottom;
    } else if (rectLeft.contains(position)) {
        setCursor(Qt::SizeHorCursor);
        return Left;
    } else if (rectRight.contains(position)) {
        setCursor(Qt::SizeHorCursor);
        return Right;
    } else if (rectInterface.contains(position)){
        setCursor(QCursor());
        return Move;
    } else {
        setCursor(QCursor());
        return None;
    }
}

Insgesamt

Somit ist es möglich, eine vollständig angepasste Anwendungsoberfläche in Qt zu erstellen. Es bleibt nur zu entscheiden, ob Sie es brauchen. Wenn Sie das System-Framing des Anwendungsfensters nicht besonders stört, sollten Sie sich wahrscheinlich nicht allzu sehr darum kümmern, aber wenn Sie trotzdem wirklich sogar die Schaltfläche zum Schließen des Anwendungsfensters mit Ihrem eigenen Erscheinungsbild gestalten möchten, dann beachten Sie bitte, dass die Der in diesem Artikel angegebene Code reicht eindeutig nicht aus, um alle Nuancen der Funktionsweise des Anwendungsfensters abzudecken. Beispielsweise gibt es keine gleichzeitige Größenänderung in Breite und Höhe. Und auch periodisch ändert sich das Aussehen des Cursors beim Bewegen nicht richtig. Obwohl ich denke, dass die Grundidee der Anpassung jetzt klar ist.

Benutzerdefinierten Qt AIMP Style Audio Player herunterladen

Videoanleitung

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

Magst du es? In sozialen Netzwerken teilen!

t
  • 21. Mai 2017 15:32

Как сделать так, что бы только когда верхнюю полосу зажимаешь, то перетаскивалось окно и что бы оно оставалось на месте?

Evgenii Legotckoi
  • 24. Mai 2017 03:28

В методах mousePressEvent, mouseMoveEvent и т.д. в этом же самом уроке показано, как определять области, в которых находится курсор мыши. Это реализовано для изменения размеров, в методе checkResizableField определяется область нахождения курсора. Аналогично можно реализовать область нахождения курсора в верхней полосе. И сделать перетаскивание только в этой области. Так что изучите внимательно урок и сделайте по аналогии.

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
A
ALO1ZE19. Oktober 2024 08:19
Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов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> в заголовочном файле не работает валидатор.
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