Шаг 224.
Библиотека Qt.
Создание нестандартного окна виджета

    На этом шаге рассмотрим создание нестандартного окна виджета.

    Класс QWidget, как и класс QPixmap, содержит метод setMask(). С его помощью можно установить маску и сделать окно виджета не квадратным, а любой другой формы. Эту возможность демонстрирует программа, окно которой показано на рис. 1.


Рис.1. Пример нестандартного окна программы

class Window : public QLabel {
private:
    QPoint  m_ptPosition;
protected:
/*для окна без заголовка нужно позаботиться о возможности его перемещения.
Для этого в классе Window переопределяются методы событий мыши
mousePressEvent() и mouseMoveEvent(), реализуя тем самым код,
необходимый для изменения расположения окна на экране. Атрибут
m_ptPosition нужен для хранения координат указателя мыши относительно
начала окна виджета*/
    virtual void mousePressEvent(QMouseEvent* pe)
    {
        m_ptPosition = pe->pos();
    }
    virtual void mouseMoveEvent(QMouseEvent* pe)
    {
        move(pe->globalPos() - m_ptPosition);
    }
public:
/*для того чтобы убрать заголовок окна, мы передаем в конструктор QLabel
значение модификации свойства окна Qt::FramelessHint*/
    Window(QWidget* pwgt = 0)
        : QLabel(pwgt,  Qt::FramelessWindowHint | Qt::Window)
    {
    }
};

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    //создается объект класса Window
    Window       win;
    //в объект pix загружается файл растрового изображения
    QPixmap      pix(":/images/image1.png");
    win.setPixmap(pix);
    /*вызовом метода setPixmap() устанавливается изображение, что можно сделать
    благодаря тому, что наш класс Window унаследован от QLabel*/
    win.setMask(pix.mask());
    win.show();
    return app.exec();
}

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

    Некоторые графические форматы, например GIF, PNG и XMP, могут содержать прозрачность. При их загрузке в конструкторе или методом load() автоматически создается маска, которую можно установить с помощью метода setMask().

    Если в растровом изображении нет маски или файловый формат ее не поддерживает, то можно поступить следующим образом: класс QPixmap содержит метод createHeuristicMask(), который позволяет создавать маски, исходя из растрового изображения. Для этого берутся значения пикселов четырех углов изображения и все пикселы с этим цветом устанавливаются прозрачными. Если все цветовые значения пикселов отличаются от самого левого верхнего пиксела, то тогда за текущее выбирается цветовое значение верхнего правого пиксела. Если же и остальные два значения отличаются от правого верхнего пиксела, то тогда за текущее значение принимается цвет самого нижнего левого пиксела.

    Есть и другой способ, при помощи которого можно обойтись без установки маски. Нужно просто сделать сам фон виджета прозрачным. Это делается вызовом метода setAttribute() и установкой в нем флага Qt::WA_TranslucentBackground. Продемонстрируем использование этого флага небольшой программой, результат исполнения которой показан на рис. 2. На нем мы видим картинку с небольшой кнопкой в виде крестика слева. Нажатие на эту кнопку завершает нашу программу.


Рис.2. Пример нестандартного окна программы с прозрачным фоном

//создаем виджет надписи (lbl)
QLabel lbl;
//устанавливаем в нем необходимые флаги для окна, чтобы убрать его декорации
lbl.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
//устанавливаем для прозрачности виджета фона атрибут Qt::WA_TranslucentBackground
lbl.setAttribute(Qt::WA_TranslucentBackground);
lbl.setPixmap(QPixmap("image1.png"));
//используем виджет кнопки нажатия
QPushButton* pcmdQuit = new QPushButton("X");
//задаем ей неизменяемый размер 16x16 пикселов
pcmdQuit->setFixedSize(16, 16);
/*для того чтобы наше приложение завершалось при нажатии этой кнопки,
соединяем ее сигнал clicked() со слотом QCoreApplicaion::quit() объекта
приложения app*/
QObject::connect(pcmdQuit, SIGNAL(clicked()), &app, SLOT(quit()));
QVBoxLayout* pvbx = new QVBoxLayout;
//кнопку размещаем на виджете надписи при помощи вертикального размещения
pvbx->addWidget(pcmdQuit);
pvbx->addStretch(1);
lbl.setLayout(pvbx);
lbl.show(); 

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

    На следующем шаге рассмотрим работу со шрифтами.




Предыдущий шаг Содержание Следующий шаг