13,010
回編集
| 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> | ||