Code for Path Stroking
/****************************************************************************
**
** (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of Qt Jambi.
**
** ** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
package com.trolltech.demos;
import com.trolltech.examples.*;
import com.trolltech.qt.core.*;
import com.trolltech.qt.gui.*;
import com.trolltech.qt.gui.QSizePolicy.*;
import java.util.*;
@QtJambiExample(name = "Path Stroke")
public class PathStrokeWidget extends QWidget {
public static void main(String args[]) {
QApplication.initialize(args);
PathStrokeWidget pathStrokeWidget = new PathStrokeWidget();
pathStrokeWidget.show();
QApplication.exec();
}
private PathStrokeRendrer m_renderer;
public enum PathMode {
CurveMode, LineMode
}
public PathStrokeWidget() {
setWindowTitle(tr("Path Stroking"));
// Setting up palette.
QPalette pal = palette();
setPalette(pal);
// Widget finalruction and property setting
m_renderer = new PathStrokeRendrer(this);
QGroupBox mainGroup = new QGroupBox(this);
mainGroup.setFixedWidth(180);
mainGroup.setTitle("Path Stroking");
QGroupBox capGroup = new QGroupBox(mainGroup);
capGroup.setAttribute(Qt.WidgetAttribute.WA_ContentsPropagated);
QRadioButton flatCap = new QRadioButton(capGroup);
QRadioButton squareCap = new QRadioButton(capGroup);
QRadioButton roundCap = new QRadioButton(capGroup);
capGroup.setTitle("Cap Style");
flatCap.setText("Flat Cap");
squareCap.setText("Square Cap");
roundCap.setText("Round Cap");
QGroupBox joinGroup = new QGroupBox(mainGroup);
joinGroup.setAttribute(Qt.WidgetAttribute.WA_ContentsPropagated);
QRadioButton bevelJoin = new QRadioButton(joinGroup);
QRadioButton miterJoin = new QRadioButton(joinGroup);
QRadioButton roundJoin = new QRadioButton(joinGroup);
joinGroup.setTitle("Join Style");
bevelJoin.setText("Bevel Join");
miterJoin.setText("Miter Join");
roundJoin.setText("Round Join");
QGroupBox styleGroup = new QGroupBox(mainGroup);
styleGroup.setAttribute(Qt.WidgetAttribute.WA_ContentsPropagated);
QRadioButton solidLine = new QRadioButton(styleGroup);
QRadioButton dashLine = new QRadioButton(styleGroup);
QRadioButton dotLine = new QRadioButton(styleGroup);
QRadioButton dashDotLine = new QRadioButton(styleGroup);
QRadioButton dashDotDotLine = new QRadioButton(styleGroup);
QRadioButton customDashLine = new QRadioButton(styleGroup);
styleGroup.setTitle("Pen Style");
QPixmap line_solid = new QPixmap("classpath:/com/trolltech/demos/PathStroke/line_solid.png");
solidLine.setIcon(new QIcon(line_solid));
solidLine.setIconSize(line_solid.size());
QPixmap line_dashed = new QPixmap("classpath:/com/trolltech/demos/PathStroke/line_dashed.png");
dashLine.setIcon(new QIcon(line_dashed));
dashLine.setIconSize(line_dashed.size());
QPixmap line_dotted = new QPixmap("classpath:/com/trolltech/demos/PathStroke/line_dotted.png");
dotLine.setIcon(new QIcon(line_dotted));
dotLine.setIconSize(line_dotted.size());
QPixmap line_dash_dot = new QPixmap("classpath:/com/trolltech/demos/PathStroke/line_dash_dot.png");
dashDotLine.setIcon(new QIcon(line_dash_dot));
dashDotLine.setIconSize(line_dash_dot.size());
QPixmap line_dash_dot_dot = new QPixmap("classpath:/com/trolltech/demos/PathStroke/line_dash_dot_dot.png");
dashDotDotLine.setIcon(new QIcon(line_dash_dot_dot));
dashDotDotLine.setIconSize(line_dash_dot_dot.size());
customDashLine.setText("Custom Style");
int fixedHeight = bevelJoin.sizeHint().height();
solidLine.setFixedHeight(fixedHeight);
dashLine.setFixedHeight(fixedHeight);
dotLine.setFixedHeight(fixedHeight);
dashDotLine.setFixedHeight(fixedHeight);
dashDotDotLine.setFixedHeight(fixedHeight);
QGroupBox pathModeGroup = new QGroupBox(mainGroup);
pathModeGroup.setAttribute(Qt.WidgetAttribute.WA_ContentsPropagated);
QRadioButton curveMode = new QRadioButton(pathModeGroup);
QRadioButton lineMode = new QRadioButton(pathModeGroup);
pathModeGroup.setTitle("Path composed of");
curveMode.setText("Curves");
lineMode.setText("Lines");
QGroupBox penWidthGroup = new QGroupBox(mainGroup);
penWidthGroup.setAttribute(Qt.WidgetAttribute.WA_ContentsPropagated);
QSlider penWidth = new QSlider(Qt.Orientation.Horizontal, penWidthGroup);
penWidth.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed);
penWidthGroup.setTitle("Pen Width");
penWidth.setRange(0, 500);
QPushButton animated = new QPushButton(mainGroup);
animated.setText("Animate");
animated.setCheckable(true);
// #endif
QPushButton showSourceButton = new QPushButton(mainGroup);
showSourceButton.setText("Show Source");
QPushButton whatsThisButton = new QPushButton(mainGroup);
whatsThisButton.setText("What's This?");
whatsThisButton.setCheckable(true);
// Layouting
QHBoxLayout viewLayout = new QHBoxLayout(this);
viewLayout.addWidget(m_renderer);
viewLayout.addWidget(mainGroup);
QVBoxLayout mainGroupLayout = new QVBoxLayout(mainGroup);
mainGroupLayout.setMargin(3);
mainGroupLayout.addWidget(capGroup);
mainGroupLayout.addWidget(joinGroup);
mainGroupLayout.addWidget(styleGroup);
mainGroupLayout.addWidget(penWidthGroup);
mainGroupLayout.addWidget(pathModeGroup);
mainGroupLayout.addWidget(animated);
mainGroupLayout.addStretch(1);
mainGroupLayout.addWidget(showSourceButton);
mainGroupLayout.addWidget(whatsThisButton);
QVBoxLayout capGroupLayout = new QVBoxLayout(capGroup);
capGroupLayout.addWidget(flatCap);
capGroupLayout.addWidget(squareCap);
capGroupLayout.addWidget(roundCap);
QVBoxLayout joinGroupLayout = new QVBoxLayout(joinGroup);
joinGroupLayout.addWidget(bevelJoin);
joinGroupLayout.addWidget(miterJoin);
joinGroupLayout.addWidget(roundJoin);
QVBoxLayout styleGroupLayout = new QVBoxLayout(styleGroup);
styleGroupLayout.addWidget(solidLine);
styleGroupLayout.addWidget(dashLine);
styleGroupLayout.addWidget(dotLine);
styleGroupLayout.addWidget(dashDotLine);
styleGroupLayout.addWidget(dashDotDotLine);
styleGroupLayout.addWidget(customDashLine);
QVBoxLayout pathModeGroupLayout = new QVBoxLayout(pathModeGroup);
pathModeGroupLayout.addWidget(curveMode);
pathModeGroupLayout.addWidget(lineMode);
QVBoxLayout penWidthLayout = new QVBoxLayout(penWidthGroup);
penWidthLayout.addWidget(penWidth);
// Set up connections
penWidth.valueChanged.connect(m_renderer, "setPenWidth(int)");
animated.toggled.connect(m_renderer, "setAnimation(boolean)");
flatCap.clicked.connect(m_renderer, "setFlatCap()");
squareCap.clicked.connect(m_renderer, "setSquareCap()");
roundCap.clicked.connect(m_renderer, "setRoundCap()");
bevelJoin.clicked.connect(m_renderer, "setBevelJoin()");
miterJoin.clicked.connect(m_renderer, "setMiterJoin()");
roundJoin.clicked.connect(m_renderer, "setRoundJoin()");
curveMode.clicked.connect(m_renderer, "setCurveMode()");
lineMode.clicked.connect(m_renderer, "setLineMode()");
solidLine.clicked.connect(m_renderer, "setSolidLine()");
dashLine.clicked.connect(m_renderer, "setDashLine()");
dotLine.clicked.connect(m_renderer, "setDotLine()");
dashDotLine.clicked.connect(m_renderer, "setDashDotLine()");
dashDotDotLine.clicked.connect(m_renderer, "setDashDotDotLine()");
customDashLine.clicked.connect(m_renderer, "setCustomDashLine()");
showSourceButton.clicked.connect(m_renderer, "showSource()");
whatsThisButton.clicked.connect(m_renderer, "setDescriptionEnabled(boolean)");
m_renderer.descriptionEnabledChanged.connect(whatsThisButton, "setChecked(boolean)");
// Set the defaults
animated.setChecked(true);
flatCap.setChecked(true);
bevelJoin.setChecked(true);
penWidth.setValue(50);
curveMode.setChecked(true);
solidLine.setChecked(true);
m_renderer.loadSourceFile("classpath:/com/trolltech/demos/PathStrokeWidget.java");
m_renderer.loadDescription("classpath:/com/trolltech/demos/PathStroke/pathstroke.html");
}
public class PathStrokeRendrer extends ArthurFrame {
private QBasicTimer m_timer = new QBasicTimer();
private PathMode m_pathMode;
private boolean m_wasAnimated;
private double m_penWidth;
private int m_pointSize;
private int m_activePoint;
private Vector<QPointF> m_points = new Vector<QPointF>();
private Vector<QPointF> m_vectors = new Vector<QPointF>();
private Qt.PenJoinStyle m_joinStyle;
private Qt.PenCapStyle m_capStyle;
private Qt.PenStyle m_penStyle;
void setPenWidth(int penWidth) {
m_penWidth = penWidth / 10.0;
update();
}
void setFlatCap() {
m_capStyle = Qt.PenCapStyle.FlatCap;
update();
}
void setSquareCap() {
m_capStyle = Qt.PenCapStyle.SquareCap;
update();
}
void setRoundCap() {
m_capStyle = Qt.PenCapStyle.RoundCap;
update();
}
void setBevelJoin() {
m_joinStyle = Qt.PenJoinStyle.BevelJoin;
update();
}
void setMiterJoin() {
m_joinStyle = Qt.PenJoinStyle.MiterJoin;
update();
}
void setRoundJoin() {
m_joinStyle = Qt.PenJoinStyle.RoundJoin;
update();
}
void setCurveMode() {
m_pathMode = PathMode.CurveMode;
update();
}
void setLineMode() {
m_pathMode = PathMode.LineMode;
update();
}
void setSolidLine() {
m_penStyle = Qt.PenStyle.SolidLine;
update();
}
void setDashLine() {
m_penStyle = Qt.PenStyle.DashLine;
update();
}
void setDotLine() {
m_penStyle = Qt.PenStyle.DotLine;
update();
}
void setDashDotLine() {
m_penStyle = Qt.PenStyle.DashDotLine;
update();
}
void setDashDotDotLine() {
m_penStyle = Qt.PenStyle.DashDotDotLine;
update();
}
void setCustomDashLine() {
m_penStyle = Qt.PenStyle.NoPen;
update();
}
@Override
public QSize sizeHint() {
return new QSize(500, 500);
}
public boolean animation() {
return m_timer.isActive();
}
public double realPenWidth() {
return m_penWidth;
}
public void setRealPenWidth(double penWidth) {
m_penWidth = penWidth;
update();
}
public PathStrokeRendrer(QWidget parent) {
super(parent);
m_pointSize = 10;
m_activePoint = -1;
m_capStyle = Qt.PenCapStyle.FlatCap;
m_joinStyle = Qt.PenJoinStyle.BevelJoin;
m_pathMode = PathMode.CurveMode;
m_penWidth = 1;
m_penStyle = Qt.PenStyle.SolidLine;
m_wasAnimated = true;
setSizePolicy(Policy.Expanding, Policy.Expanding);
}
@Override
public void paint(QPainter painter) {
if (m_points.isEmpty())
initializePoints();
painter.setRenderHint(QPainter.RenderHint.Antialiasing);
painter.setPen(Qt.PenStyle.NoPen);
// finalruct the path
QPainterPath path = new QPainterPath();
path.moveTo(m_points.elementAt(0));
if (m_pathMode == PathMode.LineMode) {
for (int i = 1; i < m_points.size(); ++i) {
path.lineTo(m_points.elementAt(i));
}
} else {
int i = 1;
while (i + 2 < m_points.size()) {
path.cubicTo(m_points.elementAt(i), m_points.elementAt(i + 1), m_points
.elementAt(i + 2));
i += 3;
}
while (i < m_points.size()) {
path.lineTo(m_points.elementAt(i));
++i;
}
}
// Draw the path
{
QColor lg = QColor.red;
// The "custom" pen
if (m_penStyle == Qt.PenStyle.NoPen) {
QPainterPathStroker stroker = new QPainterPathStroker();
stroker.setWidth(m_penWidth);
stroker.setJoinStyle(m_joinStyle);
stroker.setCapStyle(m_capStyle);
List<Double> dashes = new Vector<Double>();
Double space = new Double(4);
dashes.add(new Double(1.0));
dashes.add(space);
dashes.add(new Double(3.0));
dashes.add(space);
dashes.add(new Double(9.0));
dashes.add(space);
dashes.add(new Double(27.0));
dashes.add(space);
dashes.add(new Double(9.0));
dashes.add(space);
dashes.add(new Double(3.0));
dashes.add(space);
stroker.setDashPattern(dashes);
QPainterPath stroke = stroker.createStroke(path);
painter.fillPath(stroke, new QBrush(lg));
} else {
QPen pen = new QPen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
painter.strokePath(path, pen);
}
}
if (true) {
// Draw the control points
painter.setPen(new QColor(50, 100, 120, 200));
painter.setBrush(new QColor(200, 200, 210, 120));
for (int i = 0; i < m_points.size(); ++i) {
QPointF pos = m_points.elementAt(i);
painter.drawEllipse(new QRectF(pos.x() - m_pointSize, pos.y() - m_pointSize,
m_pointSize * 2, m_pointSize * 2));
}
painter.setPen(new QPen(QColor.lightGray, 0, Qt.PenStyle.SolidLine));
painter.setBrush(Qt.BrushStyle.NoBrush);
QPolygonF pol = new QPolygonF();
for (Iterator<QPointF> iter = m_points.iterator(); iter.hasNext();) {
QPointF element = iter.next();
pol.append(element);
}
painter.drawPolyline(pol);
}
}
void initializePoints() {
final int count = 7;
m_points.clear();
m_vectors.clear();
QMatrix m = new QMatrix();
double rot = 360 / count;
QPointF center = new QPointF(width() / 2, height() / 2);
QMatrix vm = new QMatrix();
vm.shear(2, -1);
vm.scale(3, 3);
for (int i = 0; i < count; ++i) {
m_vectors.add(m.multiplied(vm).map(new QPointF(.1f, .25f)));
m.rotate(rot);
m_points.add(m.map(new QPointF(0 + center.x(), 100 + center.y())));
}
}
public void updatePoints() {
double pad = 10;
double left = pad;
double right = width() - pad;
double top = pad;
double bottom = height() - pad;
assert (m_points.size() == m_vectors.size());
for (int i = 0; i < m_points.size(); ++i) {
if (i == m_activePoint)
continue;
QPointF pos = m_points.elementAt(i);
QPointF vec = m_vectors.elementAt(i);
pos.add(vec);
if (pos.x() < left || pos.x() > right) {
vec.setX(-vec.x());
pos.setX(pos.x() < left ? left : right);
}
if (pos.y() < top || pos.y() > bottom) {
vec.setY(-vec.y());
pos.setY(pos.y() < top ? top : bottom);
}
m_points.set(i, pos);
m_vectors.set(i, vec);
}
update();
}
@Override
public void mousePressEvent(QMouseEvent e) {
setDescriptionEnabled(false);
m_activePoint = -1;
float distance = -1;
for (int i = 0; i < m_points.size(); ++i) {
float d = (float) new QLineF(new QPointF(e.pos()), m_points.elementAt(i)).length();
if ((distance < 0 && d < 8 * m_pointSize) || d < distance) {
distance = d;
m_activePoint = i;
}
}
if (m_activePoint != -1) {
m_wasAnimated = m_timer.isActive();
setAnimation(false);
mouseMoveEvent(e);
}
}
@Override
public void mouseMoveEvent(QMouseEvent e) {
if (m_activePoint >= 0 && m_activePoint < m_points.size()) {
m_points.set(m_activePoint, new QPointF(e.pos()));
update();
}
}
@Override
public void mouseReleaseEvent(QMouseEvent e) {
m_activePoint = -1;
setAnimation(m_wasAnimated);
}
@Override
public void timerEvent(QTimerEvent e) {
if (e.timerId() == m_timer.timerId()) {
updatePoints();
QApplication.syncX();
}
}
public void setAnimation(boolean animation) {
m_timer.stop();
if (animation) {
m_timer.start(25, this);
}
}
}
}