13,032
回編集
| 351行目: | 351行目: | ||
     setTexture(palette, QPalette::Mid, midImage);  |      setTexture(palette, QPalette::Mid, midImage);  | ||
     setTexture(palette, QPalette::Window, backgroundImage);  |      setTexture(palette, QPalette::Window, backgroundImage);  | ||
 }  | |||
 </syntaxhighlight>  | |||
<br>  | |||
==== ウインドウおよびウィジェットの形状を変更する ====  | |||
ウインドウおよびウィジェットの形状を変更するには、ウィジェットの形状をプログラムで全て記述する必要がある。<br>  | |||
<br>  | |||
例えば、ボタンの形状を変更する場合、外形を描画するだけではなく、<br>  | |||
ボタンが立体的に見えるように陰影の描画、ボタン押下時の陰影の変化等も記述する必要がある。<br>  | |||
(或いは、QSS + 背景画像で形状を変更できる可能性がある)<br>  | |||
<br>  | |||
ウインドウおよびウィジェットの形状を記述するには、<code>QStyle</code>クラスを継承した派生クラスを作成して、<br>  | |||
<code>QStyle</code>クラスの<code>drawPrimitive</code>メソッドをオーバーライドする。<br>  | |||
<br>  | |||
以下の例では、ボタンの形状を変更している。<br>  | |||
Qtに付属しているサンプルを参考にしている。(<Qtのインストールディレクトリ>/examples/widgets/styles/norwegianwoodstyle.cppファイル)<br>  | |||
 <syntaxhighlight lang="c++">  | |||
 void MyStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const  | |||
 {  | |||
    switch(element)  | |||
    {  | |||
       // ウィジェットのPrimitiveの種類を指定する(ウィジェットの種類ではない)  | |||
       case PE_PanelButtonCommand:  | |||
          int delta = (option->state & State_MouseOver) ? 64 : 0;  | |||
          QColor slightlyOpaqueBlack(0, 0, 0, 63);  | |||
          QColor semiTransparentWhite(255, 255, 255, 127 + delta);  | |||
          QColor semiTransparentBlack(0, 0, 0, 127 - delta);  | |||
          int x, y, width, height;  | |||
          option->rect.getRect(&x, &y, &width, &height);  | |||
          // 以下の3行のみ追記する  | |||
          // ボタンの形状を楕円にする  | |||
          QPainterPath path;  | |||
          path.addEllipse(option->rect);  | |||
          // これ以降の記述はコピーである  | |||
          // ボタンの押下時と非押下時の陰影等を記述する  | |||
          // 様々な形状に対応している  | |||
          int radius = qMin(width, height) / 2;  | |||
          QBrush brush;  | |||
          bool darker;  | |||
          const QStyleOptionButton *buttonOption = qstyleoption_cast<const QStyleOptionButton *>(option);  | |||
          if(buttonOption && (buttonOption->features & QStyleOptionButton::Flat))  | |||
          {  | |||
             brush = option->palette.background();  | |||
             darker = (option->state & (State_Sunken | State_On));  | |||
          }  | |||
          else  | |||
          {  | |||
             if(option->state & (State_Sunken | State_On))  | |||
             {  | |||
                brush = option->palette.mid();  | |||
                darker = !(option->state & State_Sunken);  | |||
             }  | |||
             else  | |||
             {  | |||
                brush = option->palette.button();  | |||
                darker = false;  | |||
             }  | |||
          }  | |||
          painter->save();  | |||
          painter->setRenderHint(QPainter::Antialiasing, true);  | |||
          painter->fillPath(path, brush);  | |||
          if(darker)  | |||
          {  | |||
             painter->fillPath(path, slightlyOpaqueBlack);  | |||
          }  | |||
          int penWidth;  | |||
          if(radius < 10)  | |||
             penWidth = 3;  | |||
          else if (radius < 20)  | |||
             penWidth = 5;  | |||
          else  | |||
             penWidth = 7;  | |||
          QPen topPen(semiTransparentWhite, penWidth);  | |||
          QPen bottomPen(semiTransparentBlack, penWidth);  | |||
          if(option->state & (State_Sunken | State_On))  | |||
          {  | |||
             qSwap(topPen, bottomPen);  | |||
          }  | |||
          int x1 = x;  | |||
          int x2 = x + radius;  | |||
          int x3 = x + width - radius;  | |||
          int x4 = x + width;  | |||
          if(option->direction == Qt::RightToLeft)  | |||
          {  | |||
             qSwap(x1, x4);  | |||
             qSwap(x2, x3);  | |||
          }  | |||
          QPolygon topHalf;  | |||
          topHalf << QPoint(x1, y) << QPoint(x4, y) << QPoint(x3, y + radius) << QPoint(x2, y + height - radius) << QPoint(x1, y + height);  | |||
          painter->setClipPath(path);  | |||
          painter->setClipRegion(topHalf, Qt::IntersectClip);  | |||
          painter->setPen(topPen);  | |||
          painter->drawPath(path);  | |||
          QPolygon bottomHalf = topHalf;  | |||
          bottomHalf[0] = QPoint(x4, y + height);  | |||
          painter->setClipPath(path);  | |||
          painter->setClipRegion(bottomHalf, Qt::IntersectClip);  | |||
          painter->setPen(bottomPen);  | |||
          painter->drawPath(path);  | |||
          painter->setPen(option->palette.foreground().color());  | |||
          painter->setClipping(false);  | |||
          painter->drawPath(path);  | |||
          painter->restore();  | |||
          break;  | |||
       default:  | |||
          // ボタン以外はMotifStyleの形状を採用  | |||
          QMotifStyle::drawPrimitive(element, option, painter, widget);  | |||
          break;  | |||
    }  | |||
  }  |   }  | ||
  </syntaxhighlight>  |   </syntaxhighlight>  | ||