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