Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Serr500 от Января 17, 2014, 20:54



Название: Ореол вокруг виджета
Отправлено: Serr500 от Января 17, 2014, 20:54
Возникла необходимость сделать виджет, вокруг которого при попадании фокуса возникает ореол. Что-нибудь типа такого, как указано на рисунке, только поровнее, естественно...  ;) В качестве виджета может быть QWidget, QFrame, QLineEdit или что-либо ещё, поэтому будем брать самую основу и считать, что работаем с QWidget. Соответственно, вопрос: "Но, чёрт возьми, Холмс!!! Как?!!". Никогда не приходилось заниматься таким делом. Подскажите хотя бы куда копать. Может, в сторону QStyle?  ???


Название: Re: Ореол вокруг виджета
Отправлено: Igors от Января 18, 2014, 11:56
Создаете виджет W, у него layout в него вставляете того что обводить. Регулируете размер рамки ореола с помощью setContentsMargin. Ну и пишите paint для виджета W (не вижу необходимости связываться с QStyle)


Название: Re: Ореол вокруг виджета
Отправлено: mitrich от Января 18, 2014, 12:23
Вот самое удобное, на мой взгляд, решение. Будет работать для любого потомка QWidget (и для самого QWidget).
Код
C++ (Qt)
class HaloButton: public QPushButton
{
   Q_OBJECT
 
public:
   explicit HaloButton(QWidget *parent = 0);
 
protected:
   void enterEvent(QEvent *e);
   void leaveEvent(QEvent *e);
 
private:
   QGraphicsDropShadowEffect *halo;
};
 
HaloButton::HaloButton(QWidget *parent):
   QPushButton(parent)
{
   halo = new QGraphicsDropShadowEffect(this);
   halo->setXOffset(0);
   halo->setYOffset(0);
   halo->setBlurRadius(16.0);
   halo->setColor(QColor(255, 0, 0));
   halo->setEnabled(false);
 
   setGraphicsEffect(halo);
}
 
void HaloButton::enterEvent(QEvent *e)
{
   halo->setEnabled(true);
   QWidget::enterEvent(e);
}
 
void HaloButton::leaveEvent(QEvent *e)
{
   halo->setEnabled(false);
   QWidget::leaveEvent(e);
}
 
(либо focusInEvent/focusOutEvent() вместо enterEvent/leaveEvent())


Название: Re: Ореол вокруг виджета
Отправлено: Serr500 от Января 18, 2014, 16:36
Спасибо всем за подсказки. Попробую разные варианты.  :)


Название: Re: Ореол вокруг виджета
Отправлено: Fregloin от Января 19, 2014, 16:46
Как вариант установить фильтр событий, отлавливать какой виджет получил фокус, над ним рисовать прозрачный для событий виджет, задача которого рисовать ареол. что это даст, добавление функционала к существующим формам и виджетам без наследования. это как вариант.


Название: Re: Ореол вокруг виджета
Отправлено: Serr500 от Января 21, 2014, 11:52
Сделал ореол на основе QGraphicsDropShadowEffect. Выглядит чуть не так, как хотелось бы (угловато), но сойдёт. Если руки дойдут, позже сделаю поаккуратней. Однако возникла другая проблема. Связана она с комбо-боксами. Если точнее, то с popup-окнами (Qt::WindowFlags == Qt::Popup). Хотелось бы нарисовать ореол и вокруг них, но простыми способами не получается. Если брать frameless window, то с помощью метода, предложенного Igors это можно сделать. Но нужно убирать флаг Qt::Popup, а без него окно ведёт себя совершенно не так (например, не исчезает при активации другого приложения). Переписывать всю функциональность popup не хотелось бы. Может, есть какой-то встроенный в Qt механизм, позволяющий нарисовать собственный фрейм вокруг окна? Или нужно использовать нативные средства ОС и рисовать в неклиентской области, отлавливая сообщение WM_NCPAINT и ему подобное?


Название: Re: Ореол вокруг виджета
Отправлено: Igors от Января 21, 2014, 12:41
Если точнее, то с popup-окнами (Qt::WindowFlags == Qt::Popup). Хотелось бы нарисовать ореол и вокруг них, но простыми способами не получается.
С точки зрения дизайна это, мягко говоря, "небезупречно". Во всяком случае в OSX окна сами бросают тени, поэтому еще одна (или убирать системную) легко может оказаться перебором/безвкусицей.

Ну а если "вот хочется" то надо создавать прозрачное окно и в нем рисовать (недавно создавал тему "Рисование на слое").

Edit: насколько я понял, QGraphicsEffect(s) действуют только в пределах окна (если не так - поправьте)


Название: Re: Ореол вокруг виджета
Отправлено: Serr500 от Января 21, 2014, 13:15
С точки зрения дизайна это, мягко говоря, "небезупречно". Во всяком случае в OSX окна сами бросают тени, поэтому еще одна (или убирать системную) легко может оказаться перебором/безвкусицей.
Согласен, что не безупречно... Но нужно сделать именно так... Ещё одну тень не надо, надо убрать к чертям системную, т.е. заменить тень на ореол. А что касается OS X, то она даже в планах не рассматривается - всё под Win.

Ну а если "вот хочется" то надо создавать прозрачное окно и в нем рисовать (недавно создавал тему "Рисование на слое").
Вероятно, так и придётся делать.

насколько я понял, QGraphicsEffect(s) действуют только в пределах окна (если не так - поправьте)
Именно так. За границы окна приложения (а может, и виджета-родителя, не проверял) эффект не распространяется.