На этом шаге рассмотрим создание нестандартного окна виджета.
Класс 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();
Файлы приложения можно взять здесь.
На следующем шаге рассмотрим работу со шрифтами.