mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-04 16:25:27 +08:00
6.5.3 clean
This commit is contained in:
56
tests/manual/examples/widgets/itemviews/chart/CMakeLists.txt
Normal file
56
tests/manual/examples/widgets/itemviews/chart/CMakeLists.txt
Normal file
@ -0,0 +1,56 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(chart LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/chart")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(chart
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
pieview.cpp pieview.h
|
||||
)
|
||||
|
||||
set_target_properties(chart PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(chart PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(chart_resource_files
|
||||
"qtdata.cht"
|
||||
)
|
||||
|
||||
qt_add_resources(chart "chart"
|
||||
PREFIX
|
||||
"/Charts"
|
||||
FILES
|
||||
${chart_resource_files}
|
||||
)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT HAIKU AND NOT INTEGRITY AND NOT VXWORKS)
|
||||
target_link_libraries(chart PRIVATE
|
||||
m
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS chart
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
14
tests/manual/examples/widgets/itemviews/chart/chart.pro
Normal file
14
tests/manual/examples/widgets/itemviews/chart/chart.pro
Normal file
@ -0,0 +1,14 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(filedialog))
|
||||
|
||||
HEADERS = mainwindow.h \
|
||||
pieview.h
|
||||
RESOURCES = chart.qrc
|
||||
SOURCES = main.cpp \
|
||||
mainwindow.cpp \
|
||||
pieview.cpp
|
||||
unix:!mac:!vxworks:!integrity:!haiku:LIBS += -lm
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/chart
|
||||
INSTALLS += target
|
5
tests/manual/examples/widgets/itemviews/chart/chart.qrc
Normal file
5
tests/manual/examples/widgets/itemviews/chart/chart.qrc
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/Charts" >
|
||||
<file>qtdata.cht</file>
|
||||
</qresource>
|
||||
</RCC>
|
14
tests/manual/examples/widgets/itemviews/chart/main.cpp
Normal file
14
tests/manual/examples/widgets/itemviews/chart/main.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
136
tests/manual/examples/widgets/itemviews/chart/mainwindow.cpp
Normal file
136
tests/manual/examples/widgets/itemviews/chart/mainwindow.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pieview.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
QMenu *fileMenu = new QMenu(tr("&File"), this);
|
||||
QAction *openAction = fileMenu->addAction(tr("&Open..."));
|
||||
openAction->setShortcuts(QKeySequence::Open);
|
||||
QAction *saveAction = fileMenu->addAction(tr("&Save As..."));
|
||||
saveAction->setShortcuts(QKeySequence::SaveAs);
|
||||
QAction *quitAction = fileMenu->addAction(tr("E&xit"));
|
||||
quitAction->setShortcuts(QKeySequence::Quit);
|
||||
|
||||
setupModel();
|
||||
setupViews();
|
||||
|
||||
connect(openAction, &QAction::triggered, this, &MainWindow::openFile);
|
||||
connect(saveAction, &QAction::triggered, this, &MainWindow::saveFile);
|
||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||
|
||||
menuBar()->addMenu(fileMenu);
|
||||
statusBar();
|
||||
|
||||
loadFile(":/Charts/qtdata.cht");
|
||||
|
||||
setWindowTitle(tr("Chart"));
|
||||
resize(870, 550);
|
||||
}
|
||||
|
||||
void MainWindow::setupModel()
|
||||
{
|
||||
model = new QStandardItemModel(8, 2, this);
|
||||
model->setHeaderData(0, Qt::Horizontal, tr("Label"));
|
||||
model->setHeaderData(1, Qt::Horizontal, tr("Quantity"));
|
||||
}
|
||||
|
||||
void MainWindow::setupViews()
|
||||
{
|
||||
QSplitter *splitter = new QSplitter;
|
||||
QTableView *table = new QTableView;
|
||||
pieChart = new PieView;
|
||||
splitter->addWidget(table);
|
||||
splitter->addWidget(pieChart);
|
||||
splitter->setStretchFactor(0, 0);
|
||||
splitter->setStretchFactor(1, 1);
|
||||
|
||||
table->setModel(model);
|
||||
pieChart->setModel(model);
|
||||
|
||||
QItemSelectionModel *selectionModel = new QItemSelectionModel(model);
|
||||
table->setSelectionModel(selectionModel);
|
||||
pieChart->setSelectionModel(selectionModel);
|
||||
|
||||
QHeaderView *headerView = table->horizontalHeader();
|
||||
headerView->setStretchLastSection(true);
|
||||
|
||||
setCentralWidget(splitter);
|
||||
}
|
||||
|
||||
void MainWindow::openFile()
|
||||
{
|
||||
const QString fileName =
|
||||
QFileDialog::getOpenFileName(this, tr("Choose a data file"), "", "*.cht");
|
||||
if (!fileName.isEmpty())
|
||||
loadFile(fileName);
|
||||
}
|
||||
|
||||
void MainWindow::loadFile(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||
return;
|
||||
|
||||
QTextStream stream(&file);
|
||||
|
||||
model->removeRows(0, model->rowCount(QModelIndex()), QModelIndex());
|
||||
|
||||
int row = 0;
|
||||
while (!stream.atEnd()) {
|
||||
const QString line = stream.readLine();
|
||||
if (!line.isEmpty()) {
|
||||
model->insertRows(row, 1, QModelIndex());
|
||||
|
||||
const QStringList pieces = line.split(QLatin1Char(','), Qt::SkipEmptyParts);
|
||||
if (pieces.size() < 3)
|
||||
continue;
|
||||
model->setData(model->index(row, 0, QModelIndex()),
|
||||
pieces.value(0));
|
||||
model->setData(model->index(row, 1, QModelIndex()),
|
||||
pieces.value(1));
|
||||
model->setData(model->index(row, 0, QModelIndex()),
|
||||
QColor(pieces.value(2)), Qt::DecorationRole);
|
||||
row++;
|
||||
}
|
||||
};
|
||||
|
||||
file.close();
|
||||
statusBar()->showMessage(tr("Loaded %1").arg(fileName), 2000);
|
||||
}
|
||||
|
||||
void MainWindow::saveFile()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this,
|
||||
tr("Save file as"), "", "*.cht");
|
||||
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(fileName);
|
||||
if (!file.open(QFile::WriteOnly | QFile::Text))
|
||||
return;
|
||||
|
||||
QTextStream stream(&file);
|
||||
for (int row = 0; row < model->rowCount(QModelIndex()); ++row) {
|
||||
|
||||
QStringList pieces;
|
||||
|
||||
pieces.append(model->data(model->index(row, 0, QModelIndex()),
|
||||
Qt::DisplayRole).toString());
|
||||
pieces.append(model->data(model->index(row, 1, QModelIndex()),
|
||||
Qt::DisplayRole).toString());
|
||||
pieces.append(model->data(model->index(row, 0, QModelIndex()),
|
||||
Qt::DecorationRole).toString());
|
||||
|
||||
stream << pieces.join(',') << "\n";
|
||||
}
|
||||
|
||||
file.close();
|
||||
statusBar()->showMessage(tr("Saved %1").arg(fileName), 2000);
|
||||
}
|
34
tests/manual/examples/widgets/itemviews/chart/mainwindow.h
Normal file
34
tests/manual/examples/widgets/itemviews/chart/mainwindow.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAbstractItemModel;
|
||||
class QAbstractItemView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void openFile();
|
||||
void saveFile();
|
||||
|
||||
private:
|
||||
void setupModel();
|
||||
void setupViews();
|
||||
void loadFile(const QString &path);
|
||||
|
||||
QAbstractItemModel *model = nullptr;
|
||||
QAbstractItemView *pieChart = nullptr;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
506
tests/manual/examples/widgets/itemviews/chart/pieview.cpp
Normal file
506
tests/manual/examples/widgets/itemviews/chart/pieview.cpp
Normal file
@ -0,0 +1,506 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pieview.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
PieView::PieView(QWidget *parent)
|
||||
: QAbstractItemView(parent)
|
||||
{
|
||||
horizontalScrollBar()->setRange(0, 0);
|
||||
verticalScrollBar()->setRange(0, 0);
|
||||
}
|
||||
|
||||
void PieView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
|
||||
const QList<int> &roles)
|
||||
{
|
||||
QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
|
||||
|
||||
if (!roles.contains(Qt::DisplayRole))
|
||||
return;
|
||||
|
||||
validItems = 0;
|
||||
totalValue = 0.0;
|
||||
|
||||
for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
|
||||
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(index, Qt::DisplayRole).toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
totalValue += value;
|
||||
validItems++;
|
||||
}
|
||||
}
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
bool PieView::edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
|
||||
{
|
||||
if (index.column() == 0)
|
||||
return QAbstractItemView::edit(index, trigger, event);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the item that covers the coordinate given in the view.
|
||||
*/
|
||||
|
||||
QModelIndex PieView::indexAt(const QPoint &point) const
|
||||
{
|
||||
if (validItems == 0)
|
||||
return QModelIndex();
|
||||
|
||||
// Transform the view coordinates into contents widget coordinates.
|
||||
int wx = point.x() + horizontalScrollBar()->value();
|
||||
int wy = point.y() + verticalScrollBar()->value();
|
||||
|
||||
if (wx < totalSize) {
|
||||
double cx = wx - totalSize / 2;
|
||||
double cy = totalSize / 2 - wy; // positive cy for items above the center
|
||||
|
||||
// Determine the distance from the center point of the pie chart.
|
||||
double d = std::sqrt(std::pow(cx, 2) + std::pow(cy, 2));
|
||||
|
||||
if (d == 0 || d > pieSize / 2)
|
||||
return QModelIndex();
|
||||
|
||||
// Determine the angle of the point.
|
||||
double angle = qRadiansToDegrees(std::atan2(cy, cx));
|
||||
if (angle < 0)
|
||||
angle = 360 + angle;
|
||||
|
||||
// Find the relevant slice of the pie.
|
||||
double startAngle = 0.0;
|
||||
|
||||
for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
|
||||
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(index).toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
double sliceAngle = 360 * value / totalValue;
|
||||
|
||||
if (angle >= startAngle && angle < (startAngle + sliceAngle))
|
||||
return model()->index(row, 1, rootIndex());
|
||||
|
||||
startAngle += sliceAngle;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
double itemHeight = QFontMetrics(option.font).height();
|
||||
int listItem = int((wy - margin) / itemHeight);
|
||||
int validRow = 0;
|
||||
|
||||
for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
|
||||
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
if (model()->data(index).toDouble() > 0.0) {
|
||||
|
||||
if (listItem == validRow)
|
||||
return model()->index(row, 0, rootIndex());
|
||||
|
||||
// Update the list index that corresponds to the next valid row.
|
||||
++validRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
bool PieView::isIndexHidden(const QModelIndex & /*index*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the rectangle of the item at position \a index in the
|
||||
model. The rectangle is in contents coordinates.
|
||||
*/
|
||||
|
||||
QRect PieView::itemRect(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QRect();
|
||||
|
||||
// Check whether the index's row is in the list of rows represented
|
||||
// by slices.
|
||||
QModelIndex valueIndex;
|
||||
|
||||
if (index.column() != 1)
|
||||
valueIndex = model()->index(index.row(), 1, rootIndex());
|
||||
else
|
||||
valueIndex = index;
|
||||
|
||||
if (model()->data(valueIndex).toDouble() <= 0.0)
|
||||
return QRect();
|
||||
|
||||
int listItem = 0;
|
||||
for (int row = index.row()-1; row >= 0; --row) {
|
||||
if (model()->data(model()->index(row, 1, rootIndex())).toDouble() > 0.0)
|
||||
listItem++;
|
||||
}
|
||||
|
||||
switch (index.column()) {
|
||||
case 0: {
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
const qreal itemHeight = QFontMetricsF(option.font).height();
|
||||
return QRect(totalSize,
|
||||
qRound(margin + listItem * itemHeight),
|
||||
totalSize - margin, qRound(itemHeight));
|
||||
}
|
||||
case 1:
|
||||
return viewport()->rect();
|
||||
}
|
||||
return QRect();
|
||||
}
|
||||
|
||||
QRegion PieView::itemRegion(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QRegion();
|
||||
|
||||
if (index.column() != 1)
|
||||
return itemRect(index);
|
||||
|
||||
if (model()->data(index).toDouble() <= 0.0)
|
||||
return QRegion();
|
||||
|
||||
double startAngle = 0.0;
|
||||
for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
|
||||
|
||||
QModelIndex sliceIndex = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(sliceIndex).toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
double angle = 360 * value / totalValue;
|
||||
|
||||
if (sliceIndex == index) {
|
||||
QPainterPath slicePath;
|
||||
slicePath.moveTo(totalSize / 2, totalSize / 2);
|
||||
slicePath.arcTo(margin, margin, margin + pieSize, margin + pieSize,
|
||||
startAngle, angle);
|
||||
slicePath.closeSubpath();
|
||||
|
||||
return QRegion(slicePath.toFillPolygon().toPolygon());
|
||||
}
|
||||
|
||||
startAngle += angle;
|
||||
}
|
||||
}
|
||||
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
int PieView::horizontalOffset() const
|
||||
{
|
||||
return horizontalScrollBar()->value();
|
||||
}
|
||||
|
||||
void PieView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QAbstractItemView::mousePressEvent(event);
|
||||
origin = event->position().toPoint();
|
||||
if (!rubberBand)
|
||||
rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport());
|
||||
rubberBand->setGeometry(QRect(origin, QSize()));
|
||||
rubberBand->show();
|
||||
}
|
||||
|
||||
void PieView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (rubberBand)
|
||||
rubberBand->setGeometry(QRect(origin, event->position().toPoint()).normalized());
|
||||
QAbstractItemView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void PieView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QAbstractItemView::mouseReleaseEvent(event);
|
||||
if (rubberBand)
|
||||
rubberBand->hide();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
QModelIndex PieView::moveCursor(QAbstractItemView::CursorAction cursorAction,
|
||||
Qt::KeyboardModifiers /*modifiers*/)
|
||||
{
|
||||
QModelIndex current = currentIndex();
|
||||
|
||||
switch (cursorAction) {
|
||||
case MoveLeft:
|
||||
case MoveUp:
|
||||
if (current.row() > 0)
|
||||
current = model()->index(current.row() - 1, current.column(),
|
||||
rootIndex());
|
||||
else
|
||||
current = model()->index(0, current.column(), rootIndex());
|
||||
break;
|
||||
case MoveRight:
|
||||
case MoveDown:
|
||||
if (current.row() < rows(current) - 1)
|
||||
current = model()->index(current.row() + 1, current.column(),
|
||||
rootIndex());
|
||||
else
|
||||
current = model()->index(rows(current) - 1, current.column(),
|
||||
rootIndex());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
viewport()->update();
|
||||
return current;
|
||||
}
|
||||
|
||||
void PieView::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QItemSelectionModel *selections = selectionModel();
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
|
||||
QBrush background = option.palette.base();
|
||||
QPen foreground(option.palette.color(QPalette::WindowText));
|
||||
|
||||
QPainter painter(viewport());
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
painter.fillRect(event->rect(), background);
|
||||
painter.setPen(foreground);
|
||||
|
||||
// Viewport rectangles
|
||||
QRect pieRect = QRect(margin, margin, pieSize, pieSize);
|
||||
|
||||
if (validItems <= 0)
|
||||
return;
|
||||
|
||||
painter.save();
|
||||
painter.translate(pieRect.x() - horizontalScrollBar()->value(),
|
||||
pieRect.y() - verticalScrollBar()->value());
|
||||
painter.drawEllipse(0, 0, pieSize, pieSize);
|
||||
double startAngle = 0.0;
|
||||
int row;
|
||||
|
||||
for (row = 0; row < model()->rowCount(rootIndex()); ++row) {
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(index).toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
double angle = 360 * value / totalValue;
|
||||
|
||||
QModelIndex colorIndex = model()->index(row, 0, rootIndex());
|
||||
QColor color = QColor(model()->data(colorIndex, Qt::DecorationRole).toString());
|
||||
|
||||
if (currentIndex() == index)
|
||||
painter.setBrush(QBrush(color, Qt::Dense4Pattern));
|
||||
else if (selections->isSelected(index))
|
||||
painter.setBrush(QBrush(color, Qt::Dense3Pattern));
|
||||
else
|
||||
painter.setBrush(QBrush(color));
|
||||
|
||||
painter.drawPie(0, 0, pieSize, pieSize, int(startAngle*16), int(angle*16));
|
||||
|
||||
startAngle += angle;
|
||||
}
|
||||
}
|
||||
painter.restore();
|
||||
|
||||
for (row = 0; row < model()->rowCount(rootIndex()); ++row) {
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(index).toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
QModelIndex labelIndex = model()->index(row, 0, rootIndex());
|
||||
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
|
||||
option.rect = visualRect(labelIndex);
|
||||
if (selections->isSelected(labelIndex))
|
||||
option.state |= QStyle::State_Selected;
|
||||
if (currentIndex() == labelIndex)
|
||||
option.state |= QStyle::State_HasFocus;
|
||||
itemDelegate()->paint(&painter, option, labelIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PieView::resizeEvent(QResizeEvent * /* event */)
|
||||
{
|
||||
updateGeometries();
|
||||
}
|
||||
|
||||
int PieView::rows(const QModelIndex &index) const
|
||||
{
|
||||
return model()->rowCount(model()->parent(index));
|
||||
}
|
||||
|
||||
void PieView::rowsInserted(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
for (int row = start; row <= end; ++row) {
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(index).toDouble();
|
||||
|
||||
if (value > 0.0) {
|
||||
totalValue += value;
|
||||
++validItems;
|
||||
}
|
||||
}
|
||||
|
||||
QAbstractItemView::rowsInserted(parent, start, end);
|
||||
}
|
||||
|
||||
void PieView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
for (int row = start; row <= end; ++row) {
|
||||
QModelIndex index = model()->index(row, 1, rootIndex());
|
||||
double value = model()->data(index).toDouble();
|
||||
if (value > 0.0) {
|
||||
totalValue -= value;
|
||||
--validItems;
|
||||
}
|
||||
}
|
||||
|
||||
QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
|
||||
}
|
||||
|
||||
void PieView::scrollContentsBy(int dx, int dy)
|
||||
{
|
||||
viewport()->scroll(dx, dy);
|
||||
}
|
||||
|
||||
void PieView::scrollTo(const QModelIndex &index, ScrollHint)
|
||||
{
|
||||
QRect area = viewport()->rect();
|
||||
QRect rect = visualRect(index);
|
||||
|
||||
if (rect.left() < area.left()) {
|
||||
horizontalScrollBar()->setValue(
|
||||
horizontalScrollBar()->value() + rect.left() - area.left());
|
||||
} else if (rect.right() > area.right()) {
|
||||
horizontalScrollBar()->setValue(
|
||||
horizontalScrollBar()->value() + qMin(
|
||||
rect.right() - area.right(), rect.left() - area.left()));
|
||||
}
|
||||
|
||||
if (rect.top() < area.top()) {
|
||||
verticalScrollBar()->setValue(
|
||||
verticalScrollBar()->value() + rect.top() - area.top());
|
||||
} else if (rect.bottom() > area.bottom()) {
|
||||
verticalScrollBar()->setValue(
|
||||
verticalScrollBar()->value() + qMin(
|
||||
rect.bottom() - area.bottom(), rect.top() - area.top()));
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
/*
|
||||
Find the indices corresponding to the extent of the selection.
|
||||
*/
|
||||
|
||||
void PieView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
// Use content widget coordinates because we will use the itemRegion()
|
||||
// function to check for intersections.
|
||||
|
||||
QRect contentsRect = rect.translated(
|
||||
horizontalScrollBar()->value(),
|
||||
verticalScrollBar()->value()).normalized();
|
||||
|
||||
int rows = model()->rowCount(rootIndex());
|
||||
int columns = model()->columnCount(rootIndex());
|
||||
QModelIndexList indexes;
|
||||
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
for (int column = 0; column < columns; ++column) {
|
||||
QModelIndex index = model()->index(row, column, rootIndex());
|
||||
QRegion region = itemRegion(index);
|
||||
if (region.intersects(contentsRect))
|
||||
indexes.append(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (indexes.size() > 0) {
|
||||
int firstRow = indexes.at(0).row();
|
||||
int lastRow = firstRow;
|
||||
int firstColumn = indexes.at(0).column();
|
||||
int lastColumn = firstColumn;
|
||||
|
||||
for (int i = 1; i < indexes.size(); ++i) {
|
||||
firstRow = qMin(firstRow, indexes.at(i).row());
|
||||
lastRow = qMax(lastRow, indexes.at(i).row());
|
||||
firstColumn = qMin(firstColumn, indexes.at(i).column());
|
||||
lastColumn = qMax(lastColumn, indexes.at(i).column());
|
||||
}
|
||||
|
||||
QItemSelection selection(
|
||||
model()->index(firstRow, firstColumn, rootIndex()),
|
||||
model()->index(lastRow, lastColumn, rootIndex()));
|
||||
selectionModel()->select(selection, command);
|
||||
} else {
|
||||
QModelIndex noIndex;
|
||||
QItemSelection selection(noIndex, noIndex);
|
||||
selectionModel()->select(selection, command);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void PieView::updateGeometries()
|
||||
{
|
||||
horizontalScrollBar()->setPageStep(viewport()->width());
|
||||
horizontalScrollBar()->setRange(0, qMax(0, 2 * totalSize - viewport()->width()));
|
||||
verticalScrollBar()->setPageStep(viewport()->height());
|
||||
verticalScrollBar()->setRange(0, qMax(0, totalSize - viewport()->height()));
|
||||
}
|
||||
|
||||
int PieView::verticalOffset() const
|
||||
{
|
||||
return verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the position of the item in viewport coordinates.
|
||||
*/
|
||||
|
||||
QRect PieView::visualRect(const QModelIndex &index) const
|
||||
{
|
||||
QRect rect = itemRect(index);
|
||||
if (!rect.isValid())
|
||||
return rect;
|
||||
|
||||
return QRect(rect.left() - horizontalScrollBar()->value(),
|
||||
rect.top() - verticalScrollBar()->value(),
|
||||
rect.width(), rect.height());
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a region corresponding to the selection in viewport coordinates.
|
||||
*/
|
||||
|
||||
QRegion PieView::visualRegionForSelection(const QItemSelection &selection) const
|
||||
{
|
||||
int ranges = selection.count();
|
||||
|
||||
if (ranges == 0)
|
||||
return QRect();
|
||||
|
||||
QRegion region;
|
||||
for (int i = 0; i < ranges; ++i) {
|
||||
const QItemSelectionRange &range = selection.at(i);
|
||||
for (int row = range.top(); row <= range.bottom(); ++row) {
|
||||
for (int col = range.left(); col <= range.right(); ++col) {
|
||||
QModelIndex index = model()->index(row, col, rootIndex());
|
||||
region += visualRect(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
return region;
|
||||
}
|
66
tests/manual/examples/widgets/itemviews/chart/pieview.h
Normal file
66
tests/manual/examples/widgets/itemviews/chart/pieview.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PIEVIEW_H
|
||||
#define PIEVIEW_H
|
||||
|
||||
#include <QAbstractItemView>
|
||||
|
||||
//! [0]
|
||||
class PieView : public QAbstractItemView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PieView(QWidget *parent = nullptr);
|
||||
|
||||
QRect visualRect(const QModelIndex &index) const override;
|
||||
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
|
||||
QModelIndex indexAt(const QPoint &point) const override;
|
||||
|
||||
protected slots:
|
||||
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
|
||||
const QList<int> &roles = QList<int>()) override;
|
||||
void rowsInserted(const QModelIndex &parent, int start, int end) override;
|
||||
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
|
||||
|
||||
protected:
|
||||
bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) override;
|
||||
QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,
|
||||
Qt::KeyboardModifiers modifiers) override;
|
||||
|
||||
int horizontalOffset() const override;
|
||||
int verticalOffset() const override;
|
||||
|
||||
bool isIndexHidden(const QModelIndex &index) const override;
|
||||
|
||||
void setSelection(const QRect&, QItemSelectionModel::SelectionFlags command) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void scrollContentsBy(int dx, int dy) override;
|
||||
|
||||
QRegion visualRegionForSelection(const QItemSelection &selection) const override;
|
||||
|
||||
private:
|
||||
QRect itemRect(const QModelIndex &item) const;
|
||||
QRegion itemRegion(const QModelIndex &index) const;
|
||||
int rows(const QModelIndex &index = QModelIndex()) const;
|
||||
void updateGeometries() override;
|
||||
|
||||
int margin = 0;
|
||||
int totalSize = 300;
|
||||
int pieSize = totalSize - 2 * margin;
|
||||
int validItems = 0;
|
||||
double totalValue = 0.0;
|
||||
QRubberBand *rubberBand = nullptr;
|
||||
QPoint origin;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // PIEVIEW_H
|
14
tests/manual/examples/widgets/itemviews/chart/qtdata.cht
Normal file
14
tests/manual/examples/widgets/itemviews/chart/qtdata.cht
Normal file
@ -0,0 +1,14 @@
|
||||
Scientific Research,21,#99e600
|
||||
Engineering & Design,18,#99cc00
|
||||
Automotive,14,#99b300
|
||||
Aerospace,13,#9f991a
|
||||
Automation & Machine Tools,13,#a48033
|
||||
Medical & Bioinformatics,13,#a9664d
|
||||
Imaging & Special Effects,12,#ae4d66
|
||||
Defense,11,#b33380
|
||||
Test & Measurement Systems,9,#a64086
|
||||
Oil & Gas,9,#994d8d
|
||||
Entertainment & Broadcasting,7,#8d5a93
|
||||
Financial,6,#806699
|
||||
Consumer Electronics,4,#8073a6
|
||||
Other,38,#8080b3
|
@ -0,0 +1,36 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(dirview LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/dirview")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(dirview
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(dirview PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(dirview PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS dirview
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(treeview))
|
||||
|
||||
SOURCES = main.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/dirview
|
||||
INSTALLS += target
|
62
tests/manual/examples/widgets/itemviews/dirview/main.cpp
Normal file
62
tests/manual/examples/widgets/itemviews/dirview/main.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileSystemModel>
|
||||
#include <QFileIconProvider>
|
||||
#include <QScreen>
|
||||
#include <QScroller>
|
||||
#include <QTreeView>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("Qt Dir View Example");
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
QCommandLineOption dontUseCustomDirectoryIconsOption("c", "Set QFileSystemModel::DontUseCustomDirectoryIcons");
|
||||
parser.addOption(dontUseCustomDirectoryIconsOption);
|
||||
QCommandLineOption dontWatchOption("w", "Set QFileSystemModel::DontWatch");
|
||||
parser.addOption(dontWatchOption);
|
||||
parser.addPositionalArgument("directory", "The directory to start in.");
|
||||
parser.process(app);
|
||||
const QString rootPath = parser.positionalArguments().isEmpty()
|
||||
? QString() : parser.positionalArguments().first();
|
||||
|
||||
QFileSystemModel model;
|
||||
QFileIconProvider iconProvider;
|
||||
model.setIconProvider(&iconProvider);
|
||||
model.setRootPath("");
|
||||
if (parser.isSet(dontUseCustomDirectoryIconsOption))
|
||||
model.setOption(QFileSystemModel::DontUseCustomDirectoryIcons);
|
||||
if (parser.isSet(dontWatchOption))
|
||||
model.setOption(QFileSystemModel::DontWatchForChanges);
|
||||
QTreeView tree;
|
||||
tree.setModel(&model);
|
||||
if (!rootPath.isEmpty()) {
|
||||
const QModelIndex rootIndex = model.index(QDir::cleanPath(rootPath));
|
||||
if (rootIndex.isValid())
|
||||
tree.setRootIndex(rootIndex);
|
||||
}
|
||||
|
||||
// Demonstrating look and feel features
|
||||
tree.setAnimated(false);
|
||||
tree.setIndentation(20);
|
||||
tree.setSortingEnabled(true);
|
||||
const QSize availableSize = tree.screen()->availableGeometry().size();
|
||||
tree.resize(availableSize / 2);
|
||||
tree.setColumnWidth(0, tree.width() / 3);
|
||||
|
||||
// Make it flickable on touchscreens
|
||||
QScroller::grabGesture(&tree, QScroller::TouchGesture);
|
||||
|
||||
tree.setWindowTitle(QObject::tr("Dir View"));
|
||||
tree.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(interview LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/interview")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(interview
|
||||
main.cpp
|
||||
model.cpp model.h
|
||||
)
|
||||
|
||||
set_target_properties(interview PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(interview PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(interview_resource_files
|
||||
"images/folder.png"
|
||||
"images/interview.png"
|
||||
"images/services.png"
|
||||
)
|
||||
|
||||
qt_add_resources(interview "interview"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${interview_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS interview
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
2
tests/manual/examples/widgets/itemviews/interview/README
Normal file
2
tests/manual/examples/widgets/itemviews/interview/README
Normal file
@ -0,0 +1,2 @@
|
||||
The interview example shows the same model and selection being shared
|
||||
between three different views.
|
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 174 B |
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1,16 @@
|
||||
TEMPLATE = app
|
||||
QT += widgets
|
||||
requires(qtConfig(treeview))
|
||||
|
||||
HEADERS += model.h
|
||||
SOURCES += model.cpp main.cpp
|
||||
RESOURCES += interview.qrc
|
||||
|
||||
build_all:!build_pass {
|
||||
CONFIG -= build_all
|
||||
CONFIG += release
|
||||
}
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/interview
|
||||
INSTALLS += target
|
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>images/folder.png</file>
|
||||
<file>images/services.png</file>
|
||||
<file>images/interview.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
55
tests/manual/examples/widgets/itemviews/interview/main.cpp
Normal file
55
tests/manual/examples/widgets/itemviews/interview/main.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QListView>
|
||||
#include <QSplitter>
|
||||
#include <QTableView>
|
||||
#include <QTreeView>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QSplitter page;
|
||||
|
||||
QAbstractItemModel *data = new Model(1000, 10, &page);
|
||||
QItemSelectionModel *selections = new QItemSelectionModel(data);
|
||||
|
||||
QTableView *table = new QTableView;
|
||||
table->setModel(data);
|
||||
table->setSelectionModel(selections);
|
||||
table->horizontalHeader()->setSectionsMovable(true);
|
||||
table->verticalHeader()->setSectionsMovable(true);
|
||||
// Set StaticContents to enable minimal repaints on resizes.
|
||||
table->viewport()->setAttribute(Qt::WA_StaticContents);
|
||||
page.addWidget(table);
|
||||
|
||||
QTreeView *tree = new QTreeView;
|
||||
tree->setModel(data);
|
||||
tree->setSelectionModel(selections);
|
||||
tree->setUniformRowHeights(true);
|
||||
tree->header()->setStretchLastSection(false);
|
||||
tree->viewport()->setAttribute(Qt::WA_StaticContents);
|
||||
// Disable the focus rect to get minimal repaints when scrolling on Mac.
|
||||
tree->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
page.addWidget(tree);
|
||||
|
||||
QListView *list = new QListView;
|
||||
list->setModel(data);
|
||||
list->setSelectionModel(selections);
|
||||
list->setViewMode(QListView::IconMode);
|
||||
list->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
list->setAlternatingRowColors(false);
|
||||
list->viewport()->setAttribute(Qt::WA_StaticContents);
|
||||
list->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
page.addWidget(list);
|
||||
|
||||
page.setWindowIcon(QPixmap(":/images/interview.png"));
|
||||
page.setWindowTitle("Interview");
|
||||
page.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
110
tests/manual/examples/widgets/itemviews/interview/model.cpp
Normal file
110
tests/manual/examples/widgets/itemviews/interview/model.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "model.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
Model::Model(int rows, int columns, QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
services(QPixmap(":/images/services.png")),
|
||||
rc(rows),
|
||||
cc(columns),
|
||||
tree(new QList<Node>(rows, Node()))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
delete tree;
|
||||
}
|
||||
|
||||
QModelIndex Model::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (row < rc && row >= 0 && column < cc && column >= 0) {
|
||||
Node *parentNode = static_cast<Node*>(parent.internalPointer());
|
||||
Node *childNode = node(row, parentNode);
|
||||
if (childNode)
|
||||
return createIndex(row, column, childNode);
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex Model::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (child.isValid()) {
|
||||
Node *childNode = static_cast<Node*>(child.internalPointer());
|
||||
Node *parentNode = parent(childNode);
|
||||
if (parentNode)
|
||||
return createIndex(row(parentNode), 0, parentNode);
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int Model::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return (parent.isValid() && parent.column() != 0) ? 0 : rc;
|
||||
}
|
||||
|
||||
int Model::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return cc;
|
||||
}
|
||||
|
||||
QVariant Model::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (role == Qt::DisplayRole)
|
||||
return QVariant("Item " + QString::number(index.row()) + ':' + QString::number(index.column()));
|
||||
if (role == Qt::DecorationRole) {
|
||||
if (index.column() == 0)
|
||||
return iconProvider.icon(QFileIconProvider::Folder);
|
||||
return iconProvider.icon(QFileIconProvider::File);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole)
|
||||
return QString::number(section);
|
||||
if (role == Qt::DecorationRole)
|
||||
return QVariant::fromValue(services);
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
bool Model::hasChildren(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid() && parent.column() != 0)
|
||||
return false;
|
||||
return rc > 0 && cc > 0;
|
||||
}
|
||||
|
||||
Qt::ItemFlags Model::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return {};
|
||||
return Qt::ItemIsDragEnabled|QAbstractItemModel::flags(index);
|
||||
}
|
||||
|
||||
Model::Node *Model::node(int row, Node *parent) const
|
||||
{
|
||||
if (parent && !parent->children)
|
||||
parent->children = new QList<Node>(rc, Node(parent));
|
||||
QList<Node> *v = parent ? parent->children : tree;
|
||||
return const_cast<Node*>(&(v->at(row)));
|
||||
}
|
||||
|
||||
Model::Node *Model::parent(Node *child) const
|
||||
{
|
||||
return child ? child->parent : nullptr;
|
||||
}
|
||||
|
||||
int Model::row(Node *node) const
|
||||
{
|
||||
const Node *first = node->parent ? &(node->parent->children->at(0)) : &(tree->at(0));
|
||||
return node - first;
|
||||
}
|
53
tests/manual/examples/widgets/itemviews/interview/model.h
Normal file
53
tests/manual/examples/widgets/itemviews/interview/model.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QFileIconProvider>
|
||||
#include <QIcon>
|
||||
#include <QList>
|
||||
|
||||
class Model : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Model(int rows, int columns, QObject *parent = nullptr);
|
||||
~Model();
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
|
||||
bool hasChildren(const QModelIndex &parent) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
private:
|
||||
|
||||
struct Node
|
||||
{
|
||||
Node(Node *parent = nullptr) : parent(parent), children(nullptr) {}
|
||||
~Node() { delete children; }
|
||||
Node *parent;
|
||||
QList<Node> *children;
|
||||
};
|
||||
|
||||
Node *node(int row, Node *parent) const;
|
||||
Node *parent(Node *child) const;
|
||||
int row(Node *node) const;
|
||||
|
||||
QIcon services;
|
||||
int rc;
|
||||
int cc;
|
||||
QList<Node> *tree;
|
||||
QFileIconProvider iconProvider;
|
||||
};
|
||||
|
||||
#endif // MODEL_H
|
@ -0,0 +1,58 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(pixelator LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/pixelator")
|
||||
|
||||
find_package(Qt6
|
||||
REQUIRED COMPONENTS Core Gui Widgets
|
||||
OPTIONAL_COMPONENTS PrintSupport
|
||||
)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(pixelator
|
||||
imagemodel.cpp imagemodel.h
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
pixeldelegate.cpp pixeldelegate.h
|
||||
)
|
||||
|
||||
set_target_properties(pixelator PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(pixelator PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
if(TARGET Qt6::PrintSupport)
|
||||
target_link_libraries(pixelator PRIVATE Qt6::PrintSupport)
|
||||
endif()
|
||||
|
||||
# Resources:
|
||||
set(images_resource_files
|
||||
"images/qt.png"
|
||||
)
|
||||
|
||||
qt_add_resources(pixelator "images"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${images_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS pixelator
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "imagemodel.h"
|
||||
|
||||
//! [0]
|
||||
ImageModel::ImageModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
void ImageModel::setImage(const QImage &image)
|
||||
{
|
||||
beginResetModel();
|
||||
modelImage = image;
|
||||
endResetModel();
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
int ImageModel::rowCount(const QModelIndex & /* parent */) const
|
||||
{
|
||||
return modelImage.height();
|
||||
}
|
||||
|
||||
int ImageModel::columnCount(const QModelIndex & /* parent */) const
|
||||
//! [2] //! [3]
|
||||
{
|
||||
return modelImage.width();
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
QVariant ImageModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
return qGray(modelImage.pixel(index.column(), index.row()));
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
QVariant ImageModel::headerData(int /* section */,
|
||||
Qt::Orientation /* orientation */,
|
||||
int role) const
|
||||
{
|
||||
if (role == Qt::SizeHintRole)
|
||||
return QSize(1, 1);
|
||||
return QVariant();
|
||||
}
|
||||
//! [5]
|
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef IMAGEMODEL_H
|
||||
#define IMAGEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QImage>
|
||||
|
||||
//! [0]
|
||||
class ImageModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImageModel(QObject *parent = nullptr);
|
||||
|
||||
void setImage(const QImage &image);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
private:
|
||||
QImage modelImage;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // IMAGEMODEL_H
|
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>images/qt.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
tests/manual/examples/widgets/itemviews/pixelator/images/qt.png
Normal file
BIN
tests/manual/examples/widgets/itemviews/pixelator/images/qt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
15
tests/manual/examples/widgets/itemviews/pixelator/main.cpp
Normal file
15
tests/manual/examples/widgets/itemviews/pixelator/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.show();
|
||||
window.openImage(":/images/qt.png");
|
||||
return app.exec();
|
||||
}
|
214
tests/manual/examples/widgets/itemviews/pixelator/mainwindow.cpp
Normal file
214
tests/manual/examples/widgets/itemviews/pixelator/mainwindow.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "imagemodel.h"
|
||||
#include "pixeldelegate.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#if defined(QT_PRINTSUPPORT_LIB)
|
||||
#include <QtPrintSupport/qtprintsupportglobal.h>
|
||||
#if QT_CONFIG(printdialog)
|
||||
#include <QPrinter>
|
||||
#include <QPrintDialog>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//! [0]
|
||||
MainWindow::MainWindow()
|
||||
{
|
||||
//! [0]
|
||||
currentPath = QDir::homePath();
|
||||
model = new ImageModel(this);
|
||||
|
||||
QWidget *centralWidget = new QWidget;
|
||||
|
||||
//! [1]
|
||||
view = new QTableView;
|
||||
view->setShowGrid(false);
|
||||
view->horizontalHeader()->hide();
|
||||
view->verticalHeader()->hide();
|
||||
view->horizontalHeader()->setMinimumSectionSize(1);
|
||||
view->verticalHeader()->setMinimumSectionSize(1);
|
||||
view->setModel(model);
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
PixelDelegate *delegate = new PixelDelegate(this);
|
||||
view->setItemDelegate(delegate);
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QLabel *pixelSizeLabel = new QLabel(tr("Pixel size:"));
|
||||
QSpinBox *pixelSizeSpinBox = new QSpinBox;
|
||||
pixelSizeSpinBox->setMinimum(4);
|
||||
pixelSizeSpinBox->setMaximum(32);
|
||||
pixelSizeSpinBox->setValue(12);
|
||||
//! [3]
|
||||
|
||||
QMenu *fileMenu = new QMenu(tr("&File"), this);
|
||||
QAction *openAction = fileMenu->addAction(tr("&Open..."));
|
||||
openAction->setShortcuts(QKeySequence::Open);
|
||||
|
||||
printAction = fileMenu->addAction(tr("&Print..."));
|
||||
printAction->setEnabled(false);
|
||||
printAction->setShortcut(QKeySequence::Print);
|
||||
|
||||
QAction *quitAction = fileMenu->addAction(tr("E&xit"));
|
||||
quitAction->setShortcuts(QKeySequence::Quit);
|
||||
|
||||
QMenu *helpMenu = new QMenu(tr("&Help"), this);
|
||||
QAction *aboutAction = helpMenu->addAction(tr("&About"));
|
||||
|
||||
menuBar()->addMenu(fileMenu);
|
||||
menuBar()->addSeparator();
|
||||
menuBar()->addMenu(helpMenu);
|
||||
|
||||
connect(openAction, &QAction::triggered, this, &MainWindow::chooseImage);
|
||||
connect(printAction, &QAction::triggered, this, &MainWindow::printImage);
|
||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||
connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutBox);
|
||||
//! [4]
|
||||
connect(pixelSizeSpinBox, &QSpinBox::valueChanged,
|
||||
delegate, &PixelDelegate::setPixelSize);
|
||||
connect(pixelSizeSpinBox, &QSpinBox::valueChanged,
|
||||
this, &MainWindow::updateView);
|
||||
//! [4]
|
||||
|
||||
QHBoxLayout *controlsLayout = new QHBoxLayout;
|
||||
controlsLayout->addWidget(pixelSizeLabel);
|
||||
controlsLayout->addWidget(pixelSizeSpinBox);
|
||||
controlsLayout->addStretch(1);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(view);
|
||||
mainLayout->addLayout(controlsLayout);
|
||||
centralWidget->setLayout(mainLayout);
|
||||
|
||||
setCentralWidget(centralWidget);
|
||||
|
||||
setWindowTitle(tr("Pixelator"));
|
||||
resize(640, 480);
|
||||
//! [5]
|
||||
}
|
||||
//! [5]
|
||||
|
||||
void MainWindow::chooseImage()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this,
|
||||
tr("Choose an image"), currentPath, "*");
|
||||
|
||||
if (!fileName.isEmpty())
|
||||
openImage(fileName);
|
||||
}
|
||||
|
||||
void MainWindow::openImage(const QString &fileName)
|
||||
{
|
||||
QImage image;
|
||||
|
||||
if (image.load(fileName)) {
|
||||
model->setImage(image);
|
||||
if (!fileName.startsWith(":/")) {
|
||||
currentPath = fileName;
|
||||
setWindowTitle(tr("%1 - Pixelator").arg(currentPath));
|
||||
}
|
||||
|
||||
printAction->setEnabled(true);
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::printImage()
|
||||
{
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
||||
if (model->rowCount(QModelIndex())*model->columnCount(QModelIndex()) > 90000) {
|
||||
QMessageBox::StandardButton answer;
|
||||
answer = QMessageBox::question(this, tr("Large Image Size"),
|
||||
tr("The printed image may be very large. Are you sure that "
|
||||
"you want to print it?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (answer == QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
|
||||
QPrinter printer(QPrinter::HighResolution);
|
||||
|
||||
QPrintDialog dlg(&printer, this);
|
||||
dlg.setWindowTitle(tr("Print Image"));
|
||||
|
||||
if (dlg.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(&printer);
|
||||
|
||||
int rows = model->rowCount(QModelIndex());
|
||||
int columns = model->columnCount(QModelIndex());
|
||||
int sourceWidth = (columns + 1) * ItemSize;
|
||||
int sourceHeight = (rows + 1) * ItemSize;
|
||||
|
||||
painter.save();
|
||||
|
||||
double xscale = printer.pageRect(QPrinter::DevicePixel).width() / double(sourceWidth);
|
||||
double yscale = printer.pageRect(QPrinter::DevicePixel).height() / double(sourceHeight);
|
||||
double scale = qMin(xscale, yscale);
|
||||
|
||||
painter.translate(printer.paperRect(QPrinter::DevicePixel).x() + printer.pageRect(QPrinter::DevicePixel).width() / 2,
|
||||
printer.paperRect(QPrinter::DevicePixel).y() + printer.pageRect(QPrinter::DevicePixel).height() / 2);
|
||||
painter.scale(scale, scale);
|
||||
painter.translate(-sourceWidth / 2, -sourceHeight / 2);
|
||||
|
||||
QStyleOptionViewItem option;
|
||||
QModelIndex parent = QModelIndex();
|
||||
|
||||
QProgressDialog progress(tr("Printing..."), tr("Cancel"), 0, rows, this);
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
float y = ItemSize / 2;
|
||||
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
progress.setValue(row);
|
||||
qApp->processEvents();
|
||||
if (progress.wasCanceled())
|
||||
break;
|
||||
|
||||
float x = ItemSize / 2;
|
||||
|
||||
for (int column = 0; column < columns; ++column) {
|
||||
option.rect = QRect(int(x), int(y), ItemSize, ItemSize);
|
||||
view->itemDelegate()->paint(&painter, option,
|
||||
model->index(row, column, parent));
|
||||
x = x + ItemSize;
|
||||
}
|
||||
y = y + ItemSize;
|
||||
}
|
||||
progress.setValue(rows);
|
||||
|
||||
painter.restore();
|
||||
painter.end();
|
||||
|
||||
if (progress.wasCanceled()) {
|
||||
QMessageBox::information(this, tr("Printing canceled"),
|
||||
tr("The printing process was canceled."), QMessageBox::Cancel);
|
||||
}
|
||||
#else
|
||||
QMessageBox::information(this, tr("Printing canceled"),
|
||||
tr("Printing is not supported on this Qt build"), QMessageBox::Cancel);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::showAboutBox()
|
||||
{
|
||||
QMessageBox::about(this, tr("About the Pixelator example"),
|
||||
tr("This example demonstrates how a standard view and a custom\n"
|
||||
"delegate can be used to produce a specialized representation\n"
|
||||
"of data in a simple custom model."));
|
||||
}
|
||||
|
||||
//! [6]
|
||||
void MainWindow::updateView()
|
||||
{
|
||||
view->resizeColumnsToContents();
|
||||
view->resizeRowsToContents();
|
||||
}
|
||||
//! [6]
|
@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class ImageModel;
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
void openImage(const QString &fileName);
|
||||
|
||||
public slots:
|
||||
void chooseImage();
|
||||
void printImage();
|
||||
void showAboutBox();
|
||||
void updateView();
|
||||
|
||||
private:
|
||||
ImageModel *model;
|
||||
QAction *printAction;
|
||||
QString currentPath;
|
||||
QTableView *view;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
@ -0,0 +1,16 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(tableview))
|
||||
qtHaveModule(printsupport): QT += printsupport
|
||||
|
||||
HEADERS = imagemodel.h \
|
||||
mainwindow.h \
|
||||
pixeldelegate.h
|
||||
SOURCES = imagemodel.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
pixeldelegate.cpp
|
||||
RESOURCES += images.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/pixelator
|
||||
INSTALLS += target
|
@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pixeldelegate.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
//! [0]
|
||||
PixelDelegate::PixelDelegate(QObject *parent)
|
||||
: QAbstractItemDelegate(parent), pixelSize(12)
|
||||
{}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
void PixelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
//! [2]
|
||||
if (option.state & QStyle::State_Selected)
|
||||
painter->fillRect(option.rect, option.palette.highlight());
|
||||
//! [1]
|
||||
|
||||
//! [3]
|
||||
const int size = qMin(option.rect.width(), option.rect.height());
|
||||
//! [3] //! [4]
|
||||
const int brightness = index.model()->data(index, Qt::DisplayRole).toInt();
|
||||
const double radius = (size / 2.0) - (brightness / 255.0 * size / 2.0);
|
||||
if (qFuzzyIsNull(radius))
|
||||
return;
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
painter->save();
|
||||
//! [5] //! [6]
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
//! [6] //! [7]
|
||||
painter->setPen(Qt::NoPen);
|
||||
//! [7] //! [8]
|
||||
if (option.state & QStyle::State_Selected)
|
||||
//! [8] //! [9]
|
||||
painter->setBrush(option.palette.highlightedText());
|
||||
else
|
||||
//! [2]
|
||||
painter->setBrush(option.palette.text());
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
painter->drawEllipse(QRectF(option.rect.x() + option.rect.width() / 2 - radius,
|
||||
option.rect.y() + option.rect.height() / 2 - radius,
|
||||
2 * radius, 2 * radius));
|
||||
painter->restore();
|
||||
}
|
||||
//! [10]
|
||||
|
||||
//! [11]
|
||||
QSize PixelDelegate::sizeHint(const QStyleOptionViewItem & /* option */,
|
||||
const QModelIndex & /* index */) const
|
||||
{
|
||||
return QSize(pixelSize, pixelSize);
|
||||
}
|
||||
//! [11]
|
||||
|
||||
//! [12]
|
||||
void PixelDelegate::setPixelSize(int size)
|
||||
{
|
||||
pixelSize = size;
|
||||
}
|
||||
//! [12]
|
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PIXELDELEGATE_H
|
||||
#define PIXELDELEGATE_H
|
||||
|
||||
#include <QAbstractItemDelegate>
|
||||
#include <QModelIndex>
|
||||
#include <QSize>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAbstractItemModel;
|
||||
class QObject;
|
||||
class QPainter;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
static constexpr int ItemSize = 256;
|
||||
|
||||
//! [0]
|
||||
class PixelDelegate : public QAbstractItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PixelDelegate(QObject *parent = nullptr);
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
public slots:
|
||||
void setPixelSize(int size);
|
||||
|
||||
private:
|
||||
int pixelSize;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // PIXELDELEGATE_H
|
@ -0,0 +1,51 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(puzzle LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/puzzle")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(itemviews_puzzle
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
piecesmodel.cpp piecesmodel.h
|
||||
puzzlewidget.cpp puzzlewidget.h
|
||||
)
|
||||
|
||||
set_target_properties(itemviews_puzzle PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(itemviews_puzzle PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(puzzle_resource_files
|
||||
"example.jpg"
|
||||
)
|
||||
|
||||
qt_add_resources(itemviews_puzzle "puzzle"
|
||||
PREFIX
|
||||
"/images"
|
||||
FILES
|
||||
${puzzle_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS itemviews_puzzle
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
BIN
tests/manual/examples/widgets/itemviews/puzzle/example.jpg
Normal file
BIN
tests/manual/examples/widgets/itemviews/puzzle/example.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
15
tests/manual/examples/widgets/itemviews/puzzle/main.cpp
Normal file
15
tests/manual/examples/widgets/itemviews/puzzle/main.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.loadImage(QStringLiteral(":/images/example.jpg"));
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
115
tests/manual/examples/widgets/itemviews/puzzle/mainwindow.cpp
Normal file
115
tests/manual/examples/widgets/itemviews/puzzle/mainwindow.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "piecesmodel.h"
|
||||
#include "puzzlewidget.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <stdlib.h>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setupMenus();
|
||||
setupWidgets();
|
||||
model = new PiecesModel(puzzleWidget->pieceSize(), this);
|
||||
piecesList->setModel(model);
|
||||
|
||||
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
setWindowTitle(tr("Puzzle"));
|
||||
}
|
||||
|
||||
void MainWindow::openImage()
|
||||
{
|
||||
const QString directory =
|
||||
QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
|
||||
QFileDialog dialog(this, tr("Open Image"), directory);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
QStringList mimeTypeFilters;
|
||||
for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
|
||||
mimeTypeFilters.append(mimeTypeName);
|
||||
mimeTypeFilters.sort();
|
||||
dialog.setMimeTypeFilters(mimeTypeFilters);
|
||||
dialog.selectMimeTypeFilter("image/jpeg");
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
loadImage(dialog.selectedFiles().constFirst());
|
||||
}
|
||||
|
||||
void MainWindow::loadImage(const QString &fileName)
|
||||
{
|
||||
QPixmap newImage;
|
||||
if (!newImage.load(fileName)) {
|
||||
QMessageBox::warning(this, tr("Open Image"),
|
||||
tr("The image file could not be loaded."),
|
||||
QMessageBox::Close);
|
||||
return;
|
||||
}
|
||||
puzzleImage = newImage;
|
||||
setupPuzzle();
|
||||
}
|
||||
|
||||
void MainWindow::setCompleted()
|
||||
{
|
||||
QMessageBox::information(this, tr("Puzzle Completed"),
|
||||
tr("Congratulations! You have completed the puzzle!\n"
|
||||
"Click OK to start again."),
|
||||
QMessageBox::Ok);
|
||||
|
||||
setupPuzzle();
|
||||
}
|
||||
|
||||
void MainWindow::setupPuzzle()
|
||||
{
|
||||
int size = qMin(puzzleImage.width(), puzzleImage.height());
|
||||
puzzleImage = puzzleImage.copy((puzzleImage.width() - size) / 2,
|
||||
(puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->imageSize(),
|
||||
puzzleWidget->imageSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
model->addPieces(puzzleImage);
|
||||
puzzleWidget->clear();
|
||||
}
|
||||
|
||||
void MainWindow::setupMenus()
|
||||
{
|
||||
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
|
||||
QAction *openAction = fileMenu->addAction(tr("&Open..."), this, &MainWindow::openImage);
|
||||
openAction->setShortcuts(QKeySequence::Open);
|
||||
|
||||
QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QCoreApplication::quit);
|
||||
exitAction->setShortcuts(QKeySequence::Quit);
|
||||
|
||||
QMenu *gameMenu = menuBar()->addMenu(tr("&Game"));
|
||||
|
||||
gameMenu->addAction(tr("&Restart"), this, &MainWindow::setupPuzzle);
|
||||
}
|
||||
|
||||
void MainWindow::setupWidgets()
|
||||
{
|
||||
QFrame *frame = new QFrame;
|
||||
QHBoxLayout *frameLayout = new QHBoxLayout(frame);
|
||||
|
||||
puzzleWidget = new PuzzleWidget(400);
|
||||
|
||||
piecesList = new QListView;
|
||||
piecesList->setDragEnabled(true);
|
||||
piecesList->setViewMode(QListView::IconMode);
|
||||
piecesList->setIconSize(QSize(puzzleWidget->pieceSize() - 20, puzzleWidget->pieceSize() - 20));
|
||||
piecesList->setGridSize(QSize(puzzleWidget->pieceSize(), puzzleWidget->pieceSize()));
|
||||
piecesList->setSpacing(10);
|
||||
piecesList->setMovement(QListView::Snap);
|
||||
piecesList->setAcceptDrops(true);
|
||||
piecesList->setDropIndicatorShown(true);
|
||||
|
||||
PiecesModel *model = new PiecesModel(puzzleWidget->pieceSize(), this);
|
||||
piecesList->setModel(model);
|
||||
|
||||
connect(puzzleWidget, &PuzzleWidget::puzzleCompleted,
|
||||
this, &MainWindow::setCompleted, Qt::QueuedConnection);
|
||||
|
||||
frameLayout->addWidget(piecesList);
|
||||
frameLayout->addWidget(puzzleWidget);
|
||||
setCentralWidget(frame);
|
||||
}
|
41
tests/manual/examples/widgets/itemviews/puzzle/mainwindow.h
Normal file
41
tests/manual/examples/widgets/itemviews/puzzle/mainwindow.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPixmap>
|
||||
|
||||
class PuzzleWidget;
|
||||
class PiecesModel;
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void openImage();
|
||||
void loadImage(const QString &path);
|
||||
void setupPuzzle();
|
||||
|
||||
private slots:
|
||||
void setCompleted();
|
||||
|
||||
private:
|
||||
void setupMenus();
|
||||
void setupWidgets();
|
||||
|
||||
QPixmap puzzleImage;
|
||||
QListView *piecesList;
|
||||
PuzzleWidget *puzzleWidget;
|
||||
PiecesModel *model;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
168
tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.cpp
Normal file
168
tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "piecesmodel.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QMimeData>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
PiecesModel::PiecesModel(int pieceSize, QObject *parent)
|
||||
: QAbstractListModel(parent), m_PieceSize(pieceSize)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant PiecesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DecorationRole)
|
||||
return QIcon(pixmaps.value(index.row()).scaled(m_PieceSize, m_PieceSize,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
else if (role == Qt::UserRole)
|
||||
return pixmaps.value(index.row());
|
||||
else if (role == Qt::UserRole + 1)
|
||||
return locations.value(index.row());
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void PiecesModel::addPiece(const QPixmap &pixmap, const QPoint &location)
|
||||
{
|
||||
int row;
|
||||
if (QRandomGenerator::global()->bounded(2) == 1)
|
||||
row = 0;
|
||||
else
|
||||
row = pixmaps.size();
|
||||
|
||||
beginInsertRows(QModelIndex(), row, row);
|
||||
pixmaps.insert(row, pixmap);
|
||||
locations.insert(row, location);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
Qt::ItemFlags PiecesModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid())
|
||||
return (QAbstractListModel::flags(index)|Qt::ItemIsDragEnabled);
|
||||
|
||||
return Qt::ItemIsDropEnabled;
|
||||
}
|
||||
|
||||
bool PiecesModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
return false;
|
||||
|
||||
if (row >= pixmaps.size() || row + count <= 0)
|
||||
return false;
|
||||
|
||||
int beginRow = qMax(0, row);
|
||||
int endRow = qMin(row + count - 1, pixmaps.size() - 1);
|
||||
|
||||
beginRemoveRows(parent, beginRow, endRow);
|
||||
|
||||
while (beginRow <= endRow) {
|
||||
pixmaps.removeAt(beginRow);
|
||||
locations.removeAt(beginRow);
|
||||
++beginRow;
|
||||
}
|
||||
|
||||
endRemoveRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList PiecesModel::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types << "image/x-puzzle-piece";
|
||||
return types;
|
||||
}
|
||||
|
||||
QMimeData *PiecesModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
QByteArray encodedData;
|
||||
|
||||
QDataStream stream(&encodedData, QDataStream::WriteOnly);
|
||||
|
||||
for (const QModelIndex &index : indexes) {
|
||||
if (index.isValid()) {
|
||||
QPixmap pixmap = qvariant_cast<QPixmap>(data(index, Qt::UserRole));
|
||||
QPoint location = data(index, Qt::UserRole+1).toPoint();
|
||||
stream << pixmap << location;
|
||||
}
|
||||
}
|
||||
|
||||
mimeData->setData("image/x-puzzle-piece", encodedData);
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
bool PiecesModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
if (!data->hasFormat("image/x-puzzle-piece"))
|
||||
return false;
|
||||
|
||||
if (action == Qt::IgnoreAction)
|
||||
return true;
|
||||
|
||||
if (column > 0)
|
||||
return false;
|
||||
|
||||
int endRow;
|
||||
|
||||
if (!parent.isValid()) {
|
||||
if (row < 0)
|
||||
endRow = pixmaps.size();
|
||||
else
|
||||
endRow = qMin(row, pixmaps.size());
|
||||
} else {
|
||||
endRow = parent.row();
|
||||
}
|
||||
|
||||
QByteArray encodedData = data->data("image/x-puzzle-piece");
|
||||
QDataStream stream(&encodedData, QDataStream::ReadOnly);
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QPixmap pixmap;
|
||||
QPoint location;
|
||||
stream >> pixmap >> location;
|
||||
|
||||
beginInsertRows(QModelIndex(), endRow, endRow);
|
||||
pixmaps.insert(endRow, pixmap);
|
||||
locations.insert(endRow, location);
|
||||
endInsertRows();
|
||||
|
||||
++endRow;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int PiecesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : pixmaps.size();
|
||||
}
|
||||
|
||||
Qt::DropActions PiecesModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::CopyAction | Qt::MoveAction;
|
||||
}
|
||||
|
||||
void PiecesModel::addPieces(const QPixmap &pixmap)
|
||||
{
|
||||
if (!pixmaps.isEmpty()) {
|
||||
beginRemoveRows(QModelIndex(), 0, pixmaps.size() - 1);
|
||||
pixmaps.clear();
|
||||
locations.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
for (int y = 0; y < 5; ++y) {
|
||||
for (int x = 0; x < 5; ++x) {
|
||||
QPixmap pieceImage = pixmap.copy(x*m_PieceSize, y*m_PieceSize, m_PieceSize, m_PieceSize);
|
||||
addPiece(pieceImage, QPoint(x, y));
|
||||
}
|
||||
}
|
||||
}
|
45
tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.h
Normal file
45
tests/manual/examples/widgets/itemviews/puzzle/piecesmodel.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PIECESLIST_H
|
||||
#define PIECESLIST_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QPixmap>
|
||||
#include <QPoint>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMimeData;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PiecesModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PiecesModel(int pieceSize, QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
bool removeRows(int row, int count, const QModelIndex &parent) override;
|
||||
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent) override;
|
||||
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
||||
QStringList mimeTypes() const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
Qt::DropActions supportedDropActions() const override;
|
||||
|
||||
void addPiece(const QPixmap &pixmap, const QPoint &location);
|
||||
void addPieces(const QPixmap &pixmap);
|
||||
|
||||
private:
|
||||
QList<QPoint> locations;
|
||||
QList<QPixmap> pixmaps;
|
||||
|
||||
int m_PieceSize;
|
||||
};
|
||||
|
||||
#endif // PIECESLIST_H
|
15
tests/manual/examples/widgets/itemviews/puzzle/puzzle.pro
Normal file
15
tests/manual/examples/widgets/itemviews/puzzle/puzzle.pro
Normal file
@ -0,0 +1,15 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(listview))
|
||||
|
||||
HEADERS = mainwindow.h \
|
||||
piecesmodel.h \
|
||||
puzzlewidget.h
|
||||
RESOURCES = puzzle.qrc
|
||||
SOURCES = main.cpp \
|
||||
mainwindow.cpp \
|
||||
piecesmodel.cpp \
|
||||
puzzlewidget.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/puzzle
|
||||
INSTALLS += target
|
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/images">
|
||||
<file>example.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
163
tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
Normal file
163
tests/manual/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "puzzlewidget.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
|
||||
: QWidget(parent), m_ImageSize(imageSize)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
setMinimumSize(m_ImageSize, m_ImageSize);
|
||||
setMaximumSize(m_ImageSize, m_ImageSize);
|
||||
}
|
||||
|
||||
void PuzzleWidget::clear()
|
||||
{
|
||||
pieces.clear();
|
||||
highlightedRect = QRect();
|
||||
inPlace = 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void PuzzleWidget::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat("image/x-puzzle-piece"))
|
||||
event->accept();
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void PuzzleWidget::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
{
|
||||
QRect updateRect = highlightedRect;
|
||||
highlightedRect = QRect();
|
||||
update(updateRect);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
QRect updateRect = highlightedRect.united(targetSquare(event->position().toPoint()));
|
||||
|
||||
if (event->mimeData()->hasFormat("image/x-puzzle-piece")
|
||||
&& findPiece(targetSquare(event->position().toPoint())) == -1) {
|
||||
|
||||
highlightedRect = targetSquare(event->position().toPoint());
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
} else {
|
||||
highlightedRect = QRect();
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
update(updateRect);
|
||||
}
|
||||
|
||||
void PuzzleWidget::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat("image/x-puzzle-piece")
|
||||
&& findPiece(targetSquare(event->position().toPoint())) == -1) {
|
||||
|
||||
QByteArray pieceData = event->mimeData()->data("image/x-puzzle-piece");
|
||||
QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
|
||||
Piece piece;
|
||||
piece.rect = targetSquare(event->position().toPoint());
|
||||
dataStream >> piece.pixmap >> piece.location;
|
||||
|
||||
pieces.append(piece);
|
||||
|
||||
highlightedRect = QRect();
|
||||
update(piece.rect);
|
||||
|
||||
event->setDropAction(Qt::MoveAction);
|
||||
event->accept();
|
||||
|
||||
if (piece.location == piece.rect.topLeft() / pieceSize()) {
|
||||
inPlace++;
|
||||
if (inPlace == 25)
|
||||
emit puzzleCompleted();
|
||||
}
|
||||
} else {
|
||||
highlightedRect = QRect();
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
int PuzzleWidget::findPiece(const QRect &pieceRect) const
|
||||
{
|
||||
for (int i = 0, size = pieces.size(); i < size; ++i) {
|
||||
if (pieces.at(i).rect == pieceRect)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void PuzzleWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QRect square = targetSquare(event->position().toPoint());
|
||||
int found = findPiece(square);
|
||||
|
||||
if (found == -1)
|
||||
return;
|
||||
|
||||
Piece piece = pieces.takeAt(found);
|
||||
|
||||
if (piece.location == square.topLeft() / pieceSize())
|
||||
inPlace--;
|
||||
|
||||
update(square);
|
||||
|
||||
QByteArray itemData;
|
||||
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
|
||||
|
||||
dataStream << piece.pixmap << piece.location;
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData("image/x-puzzle-piece", itemData);
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setMimeData(mimeData);
|
||||
drag->setHotSpot(event->position().toPoint() - square.topLeft());
|
||||
drag->setPixmap(piece.pixmap);
|
||||
|
||||
if (drag->exec(Qt::MoveAction) == Qt::IgnoreAction) {
|
||||
pieces.insert(found, piece);
|
||||
update(targetSquare(event->position().toPoint()));
|
||||
|
||||
if (piece.location == QPoint(square.x() / pieceSize(), square.y() / pieceSize()))
|
||||
inPlace++;
|
||||
}
|
||||
}
|
||||
|
||||
void PuzzleWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.fillRect(event->rect(), Qt::white);
|
||||
|
||||
if (highlightedRect.isValid()) {
|
||||
painter.setBrush(QColor("#ffcccc"));
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
|
||||
}
|
||||
|
||||
for (const Piece &piece : pieces)
|
||||
painter.drawPixmap(piece.rect, piece.pixmap);
|
||||
}
|
||||
|
||||
const QRect PuzzleWidget::targetSquare(const QPoint &position) const
|
||||
{
|
||||
QPoint topLeft = QPoint(position.x() / pieceSize(), position.y() / pieceSize()) * pieceSize();
|
||||
return QRect(topLeft, QSize(pieceSize(), pieceSize()));
|
||||
}
|
||||
|
||||
int PuzzleWidget::pieceSize() const
|
||||
{
|
||||
return m_ImageSize / 5;
|
||||
}
|
||||
|
||||
int PuzzleWidget::imageSize() const
|
||||
{
|
||||
return m_ImageSize;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PUZZLEWIDGET_H
|
||||
#define PUZZLEWIDGET_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <QPixmap>
|
||||
#include <QList>
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDragEnterEvent;
|
||||
class QDropEvent;
|
||||
class QMouseEvent;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PuzzleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
|
||||
void clear();
|
||||
|
||||
int pieceSize() const;
|
||||
int imageSize() const;
|
||||
|
||||
signals:
|
||||
void puzzleCompleted();
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
struct Piece {
|
||||
QPixmap pixmap;
|
||||
QRect rect;
|
||||
QPoint location;
|
||||
};
|
||||
|
||||
int findPiece(const QRect &pieceRect) const;
|
||||
const QRect targetSquare(const QPoint &position) const;
|
||||
|
||||
QList<Piece> pieces;
|
||||
QRect highlightedRect;
|
||||
int inPlace;
|
||||
int m_ImageSize;
|
||||
};
|
||||
|
||||
#endif // PUZZLEWIDGET_H
|
@ -0,0 +1,40 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(simpledommodel LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/simpledommodel")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Xml)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(simpledommodel
|
||||
domitem.cpp domitem.h
|
||||
dommodel.cpp dommodel.h
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
)
|
||||
|
||||
set_target_properties(simpledommodel PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(simpledommodel PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
Qt6::Xml
|
||||
)
|
||||
|
||||
install(TARGETS simpledommodel
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "domitem.h"
|
||||
|
||||
#include <QtXml>
|
||||
|
||||
//! [0]
|
||||
DomItem::DomItem(const QDomNode &node, int row, DomItem *parent)
|
||||
: domNode(node),
|
||||
//! [0]
|
||||
// Record the item's location within its parent.
|
||||
//! [1]
|
||||
parentItem(parent),
|
||||
rowNumber(row)
|
||||
{}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
DomItem::~DomItem()
|
||||
{
|
||||
qDeleteAll(childItems);
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QDomNode DomItem::node() const
|
||||
{
|
||||
return domNode;
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
DomItem *DomItem::parent()
|
||||
{
|
||||
return parentItem;
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
DomItem *DomItem::child(int i)
|
||||
{
|
||||
DomItem *childItem = childItems.value(i);
|
||||
if (childItem)
|
||||
return childItem;
|
||||
|
||||
// if child does not yet exist, create it
|
||||
if (i >= 0 && i < domNode.childNodes().count()) {
|
||||
QDomNode childNode = domNode.childNodes().item(i);
|
||||
childItem = new DomItem(childNode, i, this);
|
||||
childItems[i] = childItem;
|
||||
}
|
||||
return childItem;
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
int DomItem::row() const
|
||||
{
|
||||
return rowNumber;
|
||||
}
|
||||
//! [6]
|
@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef DOMITEM_H
|
||||
#define DOMITEM_H
|
||||
|
||||
#include <QDomNode>
|
||||
#include <QHash>
|
||||
|
||||
//! [0]
|
||||
class DomItem
|
||||
{
|
||||
public:
|
||||
DomItem(const QDomNode &node, int row, DomItem *parent = nullptr);
|
||||
~DomItem();
|
||||
DomItem *child(int i);
|
||||
DomItem *parent();
|
||||
QDomNode node() const;
|
||||
int row() const;
|
||||
|
||||
private:
|
||||
QDomNode domNode;
|
||||
QHash<int, DomItem *> childItems;
|
||||
DomItem *parentItem;
|
||||
int rowNumber;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // DOMITEM_H
|
@ -0,0 +1,153 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "dommodel.h"
|
||||
#include "domitem.h"
|
||||
|
||||
#include <QtXml>
|
||||
|
||||
//! [0]
|
||||
DomModel::DomModel(const QDomDocument &document, QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
domDocument(document),
|
||||
rootItem(new DomItem(domDocument, 0))
|
||||
{
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
DomModel::~DomModel()
|
||||
{
|
||||
delete rootItem;
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
int DomModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 3;
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QVariant DomModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
const DomItem *item = static_cast<DomItem*>(index.internalPointer());
|
||||
|
||||
const QDomNode node = item->node();
|
||||
//! [3] //! [4]
|
||||
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return node.nodeName();
|
||||
case 1:
|
||||
{
|
||||
const QDomNamedNodeMap attributeMap = node.attributes();
|
||||
QStringList attributes;
|
||||
for (int i = 0; i < attributeMap.count(); ++i) {
|
||||
QDomNode attribute = attributeMap.item(i);
|
||||
attributes << attribute.nodeName() + "=\""
|
||||
+ attribute.nodeValue() + '"';
|
||||
}
|
||||
return attributes.join(' ');
|
||||
}
|
||||
case 2:
|
||||
return node.nodeValue().split('\n').join(' ');
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
Qt::ItemFlags DomModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
QVariant DomModel::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Name");
|
||||
case 1:
|
||||
return tr("Attributes");
|
||||
case 2:
|
||||
return tr("Value");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
QModelIndex DomModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
DomItem *parentItem;
|
||||
|
||||
if (!parent.isValid())
|
||||
parentItem = rootItem;
|
||||
else
|
||||
parentItem = static_cast<DomItem*>(parent.internalPointer());
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
DomItem *childItem = parentItem->child(row);
|
||||
if (childItem)
|
||||
return createIndex(row, column, childItem);
|
||||
return QModelIndex();
|
||||
}
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
QModelIndex DomModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (!child.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
DomItem *childItem = static_cast<DomItem*>(child.internalPointer());
|
||||
DomItem *parentItem = childItem->parent();
|
||||
|
||||
if (!parentItem || parentItem == rootItem)
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(parentItem->row(), 0, parentItem);
|
||||
}
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
int DomModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
DomItem *parentItem;
|
||||
|
||||
if (!parent.isValid())
|
||||
parentItem = rootItem;
|
||||
else
|
||||
parentItem = static_cast<DomItem*>(parent.internalPointer());
|
||||
|
||||
return parentItem->node().childNodes().count();
|
||||
}
|
||||
//! [10]
|
@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef DOMMODEL_H
|
||||
#define DOMMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDomDocument>
|
||||
#include <QModelIndex>
|
||||
|
||||
class DomItem;
|
||||
|
||||
//! [0]
|
||||
class DomModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DomModel(const QDomDocument &document, QObject *parent = nullptr);
|
||||
~DomModel();
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
private:
|
||||
QDomDocument domDocument;
|
||||
DomItem *rootItem;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // DOMMODEL_H
|
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.resize(640, 480);
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "dommodel.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QTreeView>
|
||||
#include <QMenuBar>
|
||||
#include <QFileDialog>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent),
|
||||
model(new DomModel(QDomDocument(), this)),
|
||||
view(new QTreeView(this))
|
||||
{
|
||||
fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
fileMenu->addAction(tr("&Open..."), QKeySequence::Open, this, &MainWindow::openFile);
|
||||
fileMenu->addAction(tr("E&xit"), QKeySequence::Quit, this, &QWidget::close);
|
||||
|
||||
view->setModel(model);
|
||||
|
||||
setCentralWidget(view);
|
||||
setWindowTitle(tr("Simple DOM Model"));
|
||||
}
|
||||
|
||||
void MainWindow::openFile()
|
||||
{
|
||||
QString filePath = QFileDialog::getOpenFileName(this, tr("Open File"),
|
||||
xmlPath, tr("XML files (*.xml);;HTML files (*.html);;"
|
||||
"SVG files (*.svg);;User Interface files (*.ui)"));
|
||||
|
||||
if (!filePath.isEmpty()) {
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QDomDocument document;
|
||||
if (document.setContent(&file)) {
|
||||
DomModel *newModel = new DomModel(document, this);
|
||||
view->setModel(newModel);
|
||||
delete model;
|
||||
model = newModel;
|
||||
xmlPath = filePath;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QString>
|
||||
|
||||
class DomModel;
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMenu;
|
||||
class QTreeView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void openFile();
|
||||
|
||||
private:
|
||||
DomModel *model;
|
||||
QMenu *fileMenu;
|
||||
QString xmlPath;
|
||||
QTreeView *view;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
@ -0,0 +1,14 @@
|
||||
HEADERS = domitem.h \
|
||||
dommodel.h \
|
||||
mainwindow.h
|
||||
SOURCES = domitem.cpp \
|
||||
dommodel.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp
|
||||
QT += xml widgets
|
||||
requires(qtConfig(filedialog))
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/simpledommodel
|
||||
INSTALLS += target
|
||||
|
@ -0,0 +1,37 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(simplewidgetmapper LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/simplewidgetmapper")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(simplewidgetmapper
|
||||
main.cpp
|
||||
window.cpp window.h
|
||||
)
|
||||
|
||||
set_target_properties(simplewidgetmapper PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(simplewidgetmapper PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS simplewidgetmapper
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
Window window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(datawidgetmapper))
|
||||
|
||||
HEADERS = window.h
|
||||
SOURCES = main.cpp \
|
||||
window.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/simplewidgetmapper
|
||||
INSTALLS += target
|
@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
//! [Set up widgets]
|
||||
Window::Window(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setupModel();
|
||||
|
||||
nameLabel = new QLabel(tr("Na&me:"));
|
||||
nameEdit = new QLineEdit();
|
||||
addressLabel = new QLabel(tr("&Address:"));
|
||||
addressEdit = new QTextEdit();
|
||||
ageLabel = new QLabel(tr("A&ge (in years):"));
|
||||
ageSpinBox = new QSpinBox();
|
||||
nextButton = new QPushButton(tr("&Next"));
|
||||
previousButton = new QPushButton(tr("&Previous"));
|
||||
|
||||
nameLabel->setBuddy(nameEdit);
|
||||
addressLabel->setBuddy(addressEdit);
|
||||
ageLabel->setBuddy(ageSpinBox);
|
||||
//! [Set up widgets]
|
||||
|
||||
//! [Set up the mapper]
|
||||
mapper = new QDataWidgetMapper(this);
|
||||
mapper->setModel(model);
|
||||
mapper->addMapping(nameEdit, 0);
|
||||
mapper->addMapping(addressEdit, 1);
|
||||
mapper->addMapping(ageSpinBox, 2);
|
||||
|
||||
connect(previousButton, &QAbstractButton::clicked, mapper, &QDataWidgetMapper::toPrevious);
|
||||
connect(nextButton, &QAbstractButton::clicked, mapper, &QDataWidgetMapper::toNext);
|
||||
connect(mapper, &QDataWidgetMapper::currentIndexChanged, this, &Window::updateButtons);
|
||||
//! [Set up the mapper]
|
||||
|
||||
//! [Set up the layout]
|
||||
QGridLayout *layout = new QGridLayout();
|
||||
layout->addWidget(nameLabel, 0, 0, 1, 1);
|
||||
layout->addWidget(nameEdit, 0, 1, 1, 1);
|
||||
layout->addWidget(previousButton, 0, 2, 1, 1);
|
||||
layout->addWidget(addressLabel, 1, 0, 1, 1);
|
||||
layout->addWidget(addressEdit, 1, 1, 2, 1);
|
||||
layout->addWidget(nextButton, 1, 2, 1, 1);
|
||||
layout->addWidget(ageLabel, 3, 0, 1, 1);
|
||||
layout->addWidget(ageSpinBox, 3, 1, 1, 1);
|
||||
setLayout(layout);
|
||||
|
||||
setWindowTitle(tr("Simple Widget Mapper"));
|
||||
mapper->toFirst();
|
||||
}
|
||||
//! [Set up the layout]
|
||||
|
||||
//! [Set up the model]
|
||||
void Window::setupModel()
|
||||
{
|
||||
model = new QStandardItemModel(5, 3, this);
|
||||
|
||||
QStringList names;
|
||||
names << "Alice" << "Bob" << "Carol" << "Donald" << "Emma";
|
||||
|
||||
QStringList addresses;
|
||||
addresses << "<qt>123 Main Street<br/>Market Town</qt>"
|
||||
<< "<qt>PO Box 32<br/>Mail Handling Service"
|
||||
"<br/>Service City</qt>"
|
||||
<< "<qt>The Lighthouse<br/>Remote Island</qt>"
|
||||
<< "<qt>47338 Park Avenue<br/>Big City</qt>"
|
||||
<< "<qt>Research Station<br/>Base Camp<br/>Big Mountain</qt>";
|
||||
|
||||
QStringList ages;
|
||||
ages << "20" << "31" << "32" << "19" << "26";
|
||||
|
||||
for (int row = 0; row < 5; ++row) {
|
||||
QStandardItem *item = new QStandardItem(names[row]);
|
||||
model->setItem(row, 0, item);
|
||||
item = new QStandardItem(addresses[row]);
|
||||
model->setItem(row, 1, item);
|
||||
item = new QStandardItem(ages[row]);
|
||||
model->setItem(row, 2, item);
|
||||
}
|
||||
}
|
||||
//! [Set up the model]
|
||||
|
||||
//! [Slot for updating the buttons]
|
||||
void Window::updateButtons(int row)
|
||||
{
|
||||
previousButton->setEnabled(row > 0);
|
||||
nextButton->setEnabled(row < model->rowCount() - 1);
|
||||
}
|
||||
//! [Slot for updating the buttons]
|
@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDataWidgetMapper;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QSpinBox;
|
||||
class QStandardItemModel;
|
||||
class QTextEdit;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [Window definition]
|
||||
class Window : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window(QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void updateButtons(int row);
|
||||
|
||||
private:
|
||||
void setupModel();
|
||||
|
||||
QLabel *nameLabel;
|
||||
QLabel *addressLabel;
|
||||
QLabel *ageLabel;
|
||||
QLineEdit *nameEdit;
|
||||
QTextEdit *addressEdit;
|
||||
QSpinBox *ageSpinBox;
|
||||
QPushButton *nextButton;
|
||||
QPushButton *previousButton;
|
||||
|
||||
QStandardItemModel *model;
|
||||
QDataWidgetMapper *mapper;
|
||||
};
|
||||
//! [Window definition]
|
||||
|
||||
#endif // WINDOW_H
|
@ -0,0 +1,37 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(storageview LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/itemviews/storageview")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(storageview
|
||||
main.cpp
|
||||
storagemodel.cpp storagemodel.h
|
||||
)
|
||||
|
||||
set_target_properties(storageview PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(storageview PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS storageview
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
32
tests/manual/examples/widgets/itemviews/storageview/main.cpp
Normal file
32
tests/manual/examples/widgets/itemviews/storageview/main.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2016 Ivan Komissarov
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
#include <QShortcut>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "storagemodel.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
QTreeView view;
|
||||
view.resize(640, 480);
|
||||
view.setWindowTitle("Storage View");
|
||||
view.setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
StorageModel *model = new StorageModel(&view);
|
||||
model->refresh();
|
||||
QShortcut *refreshShortcut = new QShortcut(QKeySequence::Refresh, &view);
|
||||
QObject::connect(refreshShortcut, &QShortcut::activated, model, &StorageModel::refresh);
|
||||
view.setModel(model);
|
||||
|
||||
int columnCount = view.model()->columnCount();
|
||||
for (int c = 0; c < columnCount; ++c)
|
||||
view.resizeColumnToContents(c);
|
||||
view.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2016 Ivan Komissarov
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "storagemodel.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QLocale>
|
||||
|
||||
void StorageModel::refresh()
|
||||
{
|
||||
beginResetModel();
|
||||
m_volumes = QStorageInfo::mountedVolumes();
|
||||
std::sort(m_volumes.begin(), m_volumes.end(),
|
||||
[](const QStorageInfo &st1, const QStorageInfo &st2) {
|
||||
static const QString rootSortString = QStringLiteral(" ");
|
||||
return (st1.isRoot() ? rootSortString : st1.rootPath())
|
||||
< (st2.isRoot() ? rootSortString : st2.rootPath());
|
||||
});
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int StorageModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return ColumnCount;
|
||||
}
|
||||
|
||||
int StorageModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return m_volumes.count();
|
||||
}
|
||||
|
||||
Qt::ItemFlags StorageModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags result = QAbstractTableModel::flags(index);
|
||||
switch (index.column()) {
|
||||
case ColumnAvailable:
|
||||
case ColumnIsReady:
|
||||
case ColumnIsReadOnly:
|
||||
case ColumnIsValid:
|
||||
result |= Qt::ItemIsUserCheckable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant StorageModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
const QStorageInfo &volume = m_volumes.at(index.row());
|
||||
switch (index.column()) {
|
||||
case ColumnRootPath:
|
||||
return QDir::toNativeSeparators(volume.rootPath());
|
||||
case ColumnName:
|
||||
return volume.name();
|
||||
case ColumnDevice:
|
||||
return volume.device();
|
||||
case ColumnFileSystemName:
|
||||
return volume.fileSystemType();
|
||||
case ColumnTotal:
|
||||
return QLocale().formattedDataSize(volume.bytesTotal());
|
||||
case ColumnFree:
|
||||
return QLocale().formattedDataSize(volume.bytesFree());
|
||||
case ColumnAvailable:
|
||||
return QLocale().formattedDataSize(volume.bytesAvailable());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (role == Qt::CheckStateRole) {
|
||||
const QStorageInfo &volume = m_volumes.at(index.row());
|
||||
switch (index.column()) {
|
||||
case ColumnIsReady:
|
||||
return volume.isReady();
|
||||
case ColumnIsReadOnly:
|
||||
return volume.isReadOnly();
|
||||
case ColumnIsValid:
|
||||
return volume.isValid();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (role == Qt::TextAlignmentRole) {
|
||||
switch (index.column()) {
|
||||
case ColumnTotal:
|
||||
case ColumnFree:
|
||||
case ColumnAvailable:
|
||||
return Qt::AlignTrailing;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Qt::AlignLeading;
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
QLocale locale;
|
||||
const QStorageInfo &volume = m_volumes.at(index.row());
|
||||
return tr("Root path : %1\n"
|
||||
"Name: %2\n"
|
||||
"Display Name: %3\n"
|
||||
"Device: %4\n"
|
||||
"FileSystem: %5\n"
|
||||
"Total size: %6\n"
|
||||
"Free size: %7\n"
|
||||
"Available size: %8\n"
|
||||
"Is Ready: %9\n"
|
||||
"Is Read-only: %10\n"
|
||||
"Is Valid: %11\n"
|
||||
"Is Root: %12"
|
||||
).
|
||||
arg(QDir::toNativeSeparators(volume.rootPath())).
|
||||
arg(volume.name()).
|
||||
arg(volume.displayName()).
|
||||
arg(QString::fromUtf8(volume.device())).
|
||||
arg(QString::fromUtf8(volume.fileSystemType())).
|
||||
arg(locale.formattedDataSize(volume.bytesTotal())).
|
||||
arg(locale.formattedDataSize(volume.bytesFree())).
|
||||
arg(locale.formattedDataSize(volume.bytesAvailable())).
|
||||
arg(volume.isReady() ? tr("true") : tr("false")).
|
||||
arg(volume.isReadOnly() ? tr("true") : tr("false")).
|
||||
arg(volume.isValid() ? tr("true") : tr("false")).
|
||||
arg(volume.isRoot() ? tr("true") : tr("false"));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant StorageModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch (section) {
|
||||
case ColumnRootPath:
|
||||
return tr("Root Path");
|
||||
case ColumnName:
|
||||
return tr("Volume Name");
|
||||
case ColumnDevice:
|
||||
return tr("Device");
|
||||
case ColumnFileSystemName:
|
||||
return tr("File System");
|
||||
case ColumnTotal:
|
||||
return tr("Total");
|
||||
case ColumnFree:
|
||||
return tr("Free");
|
||||
case ColumnAvailable:
|
||||
return tr("Available");
|
||||
case ColumnIsReady:
|
||||
return tr("Ready");
|
||||
case ColumnIsReadOnly:
|
||||
return tr("Read-only");
|
||||
case ColumnIsValid:
|
||||
return tr("Valid");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2016 Ivan Komissarov
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef STORAGEMODEL_H
|
||||
#define STORAGEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStorageInfo>
|
||||
|
||||
class StorageModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(StorageModel)
|
||||
public:
|
||||
enum Column {
|
||||
ColumnRootPath = 0,
|
||||
ColumnName,
|
||||
ColumnDevice,
|
||||
ColumnFileSystemName,
|
||||
ColumnTotal,
|
||||
ColumnFree,
|
||||
ColumnAvailable,
|
||||
ColumnIsReady,
|
||||
ColumnIsReadOnly,
|
||||
ColumnIsValid,
|
||||
ColumnCount
|
||||
};
|
||||
|
||||
using QAbstractTableModel::QAbstractTableModel;
|
||||
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
QList<QStorageInfo> m_volumes;
|
||||
};
|
||||
|
||||
#endif // STORAGEMODEL_H
|
@ -0,0 +1,12 @@
|
||||
QT += core gui widgets
|
||||
requires(qtConfig(treeview))
|
||||
TARGET = storageview
|
||||
TEMPLATE = app
|
||||
SOURCES += storagemodel.cpp \
|
||||
main.cpp
|
||||
HEADERS += \
|
||||
storagemodel.h
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/itemviews/storageview
|
||||
INSTALLS += target
|
Reference in New Issue
Block a user