#!/usr/bin/env python ############################################################################ # # Copyright (C) 2004-2005 Trolltech AS. All rights reserved. # # This file is part of the example classes of the Qt Toolkit. # # This file may be used under the terms of the GNU General Public # License version 2.0 as published by the Free Software Foundation # and appearing in the file LICENSE.GPL included in the packaging of # self file. Please review the following information to ensure GNU # General Public Licensing requirements will be met: # http://www.trolltech.com/products/qt/opensource.html # # If you are unsure which license is appropriate for your use, please # review the following information: # http://www.trolltech.com/products/qt/licensing.html or contact the # sales department at sales@trolltech.com. # # This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE # WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. # ############################################################################ import sys from PyQt4 import QtCore, QtGui import pixelator_rc ItemSize = 256 class PixelDelegate(QtGui.QAbstractItemDelegate): def __init__(self, parent=None): QtGui.QAbstractItemDelegate.__init__(self,parent) self.pixelSize = 12 def paint(self, painter, option, index): painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setPen(QtCore.Qt.NoPen) if option.state & QtGui.QStyle.State_Selected: painter.setBrush(option.palette.highlight()) else: painter.setBrush(QtGui.QBrush(QtCore.Qt.white)) painter.drawRect(option.rect) if option.state & QtGui.QStyle.State_Selected: painter.setBrush(option.palette.highlightedText()) else: painter.setBrush(QtGui.QBrush(QtCore.Qt.black)) size = min(option.rect.width(), option.rect.height()) brightness, ok = index.model().data(index, QtCore.Qt.DisplayRole).toInt() radius = (size/2.0) - (brightness/255.0 * size/2.0) painter.drawEllipse(QtCore.QRectF( option.rect.x() + option.rect.width()/2 - radius, option.rect.y() + option.rect.height()/2 - radius, 2*radius, 2*radius)) def sizeHint(self, option, index): return QtCore.QSize(self.pixelSize, self.pixelSize) def setPixelSize(self, size): self.pixelSize = size class ImageModel(QtCore.QAbstractTableModel): def __init__(self, image, parent=None): QtCore.QAbstractTableModel.__init__(self, parent) self.modelImage = QtGui.QImage(image) def rowCount(self, parent): return self.modelImage.height() def columnCount(self, parent): return self.modelImage.width() def data(self, index, role): if not index.isValid(): return QtCore.QVariant() elif role != QtCore.Qt.DisplayRole: return QtCore.QVariant() return QtCore.QVariant(QtGui.qGray(self.modelImage.pixel(index.column(), index.row()))) class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.currentPath = QtCore.QDir.home().absolutePath() self.model = ImageModel(QtGui.QImage(), self) centralWidget = QtGui.QWidget() self.view = QtGui.QTableView() self.view.setShowGrid(False) self.view.horizontalHeader().hide() self.view.verticalHeader().hide() delegate = PixelDelegate(self) self.view.setItemDelegate(delegate) pixelSizeLabel = QtGui.QLabel(self.tr("Pixel size:")) pixelSizeSpinBox = QtGui.QSpinBox() pixelSizeSpinBox.setMinimum(1) pixelSizeSpinBox.setMaximum(32) pixelSizeSpinBox.setValue(12) fileMenu = QtGui.QMenu(self.tr("&File"), self) openAction = fileMenu.addAction(self.tr("&Open...")) openAction.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+O"))) self.printAction = fileMenu.addAction(self.tr("&Print...")) self.printAction.setEnabled(False) self.printAction.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+P"))) quitAction = fileMenu.addAction(self.tr("E&xit")) quitAction.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+Q"))) helpMenu = QtGui.QMenu(self.tr("&Help"), self) aboutAction = helpMenu.addAction(self.tr("&About")) self.menuBar().addMenu(fileMenu) self.menuBar().addSeparator() self.menuBar().addMenu(helpMenu) self.connect(openAction, QtCore.SIGNAL("triggered()"), self.chooseImage) self.connect(self.printAction, QtCore.SIGNAL("triggered()"), self.printImage) self.connect(quitAction, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("quit()")) self.connect(aboutAction, QtCore.SIGNAL("triggered()"), self.showAboutBox) self.connect(pixelSizeSpinBox, QtCore.SIGNAL("valueChanged(int)"), delegate.setPixelSize) self.connect(pixelSizeSpinBox, QtCore.SIGNAL("valueChanged(int)"), self.updateView) controlsLayout = QtGui.QHBoxLayout() controlsLayout.addWidget(pixelSizeLabel) controlsLayout.addWidget(pixelSizeSpinBox) controlsLayout.addStretch(1) mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(self.view) mainLayout.addLayout(controlsLayout) centralWidget.setLayout(mainLayout) self.setCentralWidget(centralWidget) self.setWindowTitle(self.tr("Pixelator")) self.resize(640,480) def chooseImage(self): fileName = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose an Image"), self.currentPath, "*") if not fileName.isEmpty(): self.openImage(fileName) def openImage(self, fileName): image = QtGui.QImage() if image.load(fileName): newModel = ImageModel(image, self) self.view.setModel(newModel) self.model = newModel if not fileName.startsWith(":/"): self.currentPath = fileName self.setWindowTitle(self.tr("%1 - Pixelator").arg(self.currentPath)) self.printAction.setEnabled(True) self.updateView() def printImage(self): if self.model.rowCount(QtCore.QModelIndex()) * self.model.columnCount(QtCore.QModelIndex()) > 90000: answer = QtGui.QMessageBox.question(self, self.tr("Large Image Size"), self.tr("The printed image may be very " "large. Are you sure that you want " "to print it?"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if answer == QtGui.QMessageBox.No: return printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution) dlg = QtGui.QPrintDialog(printer, self) dlg.setWindowTitle(self.tr("Print Image")) if dlg.exec_() != QtGui.QDialog.Accepted: return painter = QtGui.QPainter() painter.begin(printer) rows = self.model.rowCount(QtCore.QModelIndex()) columns = self.model.columnCount(QtCore.QModelIndex()) sourceWidth = (columns+1) * ItemSize sourceHeight = (rows+1) * ItemSize painter.save() xscale = printer.pageRect().width() / float(sourceWidth) yscale = printer.pageRect().height() / float(sourceHeight) scale = min(xscale, yscale) painter.translate(printer.pageRect().x()+printer.pageRect().width()/2, printer.pageRect().y()+printer.pageRect().height()/2) painter.scale(scale, scale) painter.translate(-sourceWidt/2, -sourceHeight/2) option = QtGui.QStyleOptionViewItem() parent = QtCore.QModelIndex() progress = QtGui.QProgressDialog(self.tr("Printing..."), self.tr("Cancel..."), 0, rows, self) y = ItemSize / 2.0 for row in range(rows): progress.setValue(row) QtGui.qApp.processEvents() if progress.wasCanceled(): break x = ItemSize / 2.0 for col in range(columns): option.rect = QtCore.QRect(x, y, ItemSize, ItemSize) self.view.itemDelegate.paint(painter, option, self.model.index(row, column, parent)) x = x + ItemSize y = y + ItemSize progress.setValue(rows) painter.restore() painter.end() if progress.wasCanceled(): QtGui.QMessageBox.information(self, self.tr("Printing canceled"), self.tr("The printing process was canceled."), QtGui.QMessageBox.Cancel) def showAboutBox(self): QtGui.QMessageBox.about(self, self.tr("About the Pixelator example"), self.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.")) def updateView(self): for row in range(self.model.rowCount(QtCore.QModelIndex())): self.view.resizeRowToContents(row) for column in range(self.model.columnCount(QtCore.QModelIndex())): self.view.resizeColumnToContents(column) if __name__ == "__main__": app = QtGui.QApplication(sys.argv) window = MainWindow() window.show() window.openImage(QtCore.QString(":/images/qt.png")) sys.exit(app.exec_())