Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- '''PyQt collapsible GroupBox
- http://code.google.com/p/blur-dev/
- '''
- ##
- # \namespace blurdev.gui.widgets.accordianwidget.accordianitem
- #
- # \remarks The container class for a widget that is collapsible within the accordian widget system
- #
- # \author [email protected]
- # \author Blur Studio
- # \date 04/29/10
- #
- #
- from PyQt4.QtGui import QGroupBox
- class AccordianItem( QGroupBox ):
- def __init__( self, accordian, title, widget ):
- QGroupBox.__init__( self, accordian )
- # create the layout
- from PyQt4.QtCore import Qt
- from PyQt4.QtGui import QVBoxLayout
- layout = QVBoxLayout()
- layout.setContentsMargins( 6, 6, 6, 6 )
- layout.setSpacing( 0 )
- layout.addWidget( widget )
- self._accordianWidget = accordian
- self._rolloutStyle = 2
- self._dragDropMode = 0
- self.setAcceptDrops(True)
- self.setLayout( layout )
- self.setContextMenuPolicy( Qt.CustomContextMenu )
- self.customContextMenuRequested.connect( self.showMenu )
- # create custom properties
- self._widget = widget
- self._collapsed = False
- self._collapsible = True
- self._clicked = False
- self._customData = {}
- from PyQt4.QtGui import QPixmap
- import os.path
- self._pixmap = QPixmap( os.path.split( __file__ )[0] + '/img/triangle.png' )
- # set common properties
- self.setTitle( title )
- def accordianWidget( self ):
- """
- \remarks grabs the parent item for the accordian widget
- \return <blurdev.gui.widgets.accordianwidget.AccordianWidget>
- """
- return self._accordianWidget
- def customData( self, key, default = None ):
- """
- \remarks return a custom pointer to information stored with this item
- \param key <str>
- \param default <variant> default value to return if the key was not found
- \return <variant> data
- """
- return self._customData.get( str(key), default )
- def dragEnterEvent( self, event ):
- if ( not self._dragDropMode ):
- return
- source = event.source()
- if ( source != self and source.parent() == self.parent() and isinstance( source, AccordianItem ) ):
- event.acceptProposedAction()
- def dragDropRect( self ):
- from PyQt4.QtCore import QRect
- return QRect( 25, 7, 10, 6 )
- def dragDropMode( self ):
- return self._dragDropMode
- def dragMoveEvent( self, event ):
- if ( not self._dragDropMode ):
- return
- source = event.source()
- if ( source != self and source.parent() == self.parent() and isinstance( source, AccordianItem ) ):
- event.acceptProposedAction()
- def dropEvent( self, event ):
- widget = event.source()
- layout = self.parent().layout()
- layout.insertWidget( layout.indexOf(self), widget )
- self._accordianWidget.emitItemsReordered()
- def expandCollapseRect( self ):
- from PyQt4.QtCore import QRect
- return QRect( 0, 0, self.width(), 20 )
- def enterEvent( self, event ):
- self.accordianWidget().leaveEvent( event )
- event.accept()
- def leaveEvent( self, event ):
- self.accordianWidget().enterEvent( event )
- event.accept()
- def mouseReleaseEvent( self, event ):
- if ( self._clicked and self.expandCollapseRect().contains( event.pos() ) ):
- self.toggleCollapsed()
- event.accept()
- else:
- event.ignore()
- self._clicked = False
- def mouseMoveEvent( self, event ):
- event.ignore()
- def mousePressEvent( self, event ):
- # handle an internal move
- from PyQt4.QtCore import Qt
- # start a drag event
- if ( event.button() == Qt.LeftButton and self.dragDropRect().contains( event.pos() ) ):
- from PyQt4.QtCore import QMimeData
- from PyQt4.QtGui import QDrag, QPixmap
- # create the pixmap
- pixmap = QPixmap.grabWidget( self, self.rect() )
- # create the mimedata
- mimeData = QMimeData()
- mimeData.setText( 'ItemTitle::%s' % (self.title()) )
- # create the drag
- drag = QDrag(self)
- drag.setMimeData( mimeData )
- drag.setPixmap( pixmap )
- drag.setHotSpot( event.pos() )
- if ( not drag.exec_() ):
- self._accordianWidget.emitItemDragFailed(self)
- event.accept()
- # determine if the expand/collapse should occur
- elif ( event.button() == Qt.LeftButton and self.expandCollapseRect().contains( event.pos() ) ):
- self._clicked = True
- event.accept()
- else:
- event.ignore()
- def isCollapsed( self ):
- return self._collapsed
- def isCollapsible( self ):
- return self._collapsible
- def paintEvent( self, event ):
- from PyQt4.QtCore import Qt
- from PyQt4.QtGui import QPainter, QPainterPath, QPalette, QPixmap, QPen
- painter = QPainter()
- painter.begin( self )
- painter.setRenderHint( painter.Antialiasing )
- x = self.rect().x()
- y = self.rect().y()
- w = self.rect().width() - 1
- h = self.rect().height() - 1
- r = 8
- # draw a rounded style
- if ( self._rolloutStyle == 2 ):
- # draw the text
- painter.drawText( x + 22, y + 3, w, 16, Qt.AlignLeft | Qt.AlignTop, self.title() )
- # draw the triangle
- pixmap = self._pixmap
- if ( not self.isCollapsed() ):
- from PyQt4.QtGui import QMatrix
- pixmap = pixmap.transformed( QMatrix().rotate(90) )
- painter.drawPixmap( x + 7, y + 4, pixmap )
- # draw the borders
- pen = QPen( self.palette().color( QPalette.Light ) )
- pen.setWidthF( 0.6 )
- painter.setPen( pen )
- painter.drawRoundedRect( x + 1, y + 1, w - 1, h - 1, r, r )
- pen.setColor( self.palette().color( QPalette.Shadow ) )
- painter.setPen( pen )
- painter.drawRoundedRect( x, y, w - 1, h - 1, r, r )
- # draw a boxed style
- elif ( self._rolloutStyle == 1 ):
- from PyQt4.QtCore import QRect
- if ( self.isCollapsed() ):
- arect = QRect( x + 1, y + 9, w - 1, 4 )
- brect = QRect( x, y + 8, w - 1, 4 )
- text = '+'
- else:
- arect = QRect( x + 1, y + 9, w - 1, h - 9 )
- brect = QRect( x, y + 8, w - 1, h - 9 )
- text = '-'
- # draw the borders
- pen = QPen( self.palette().color( QPalette.Light ) )
- pen.setWidthF( 0.6 )
- painter.setPen( pen )
- painter.drawRect( arect )
- pen.setColor( self.palette().color( QPalette.Shadow ) )
- painter.setPen( pen )
- painter.drawRect( brect )
- painter.setRenderHint( painter.Antialiasing, False )
- painter.setBrush( self.palette().color( QPalette.Window ).darker( 120 ) )
- painter.drawRect( x + 10, y + 1, w - 20, 16 )
- painter.drawText( x + 16, y + 1, w - 32, 16, Qt.AlignLeft | Qt.AlignVCenter, text )
- painter.drawText( x + 10, y + 1, w - 20, 16, Qt.AlignCenter, self.title() )
- if ( self.dragDropMode() ):
- rect = self.dragDropRect()
- # draw the lines
- l = rect.left()
- r = rect.right()
- cy = rect.center().y()
- for y in (cy - 3, cy, cy + 3):
- painter.drawLine( l, y, r, y )
- painter.end()
- def setCollapsed( self, state = True ):
- if ( self.isCollapsible() ):
- accord = self.accordianWidget()
- accord.setUpdatesEnabled(False)
- self._collapsed = state
- if ( state ):
- self.setMinimumHeight( 22 )
- self.setMaximumHeight( 22 )
- self.widget().setVisible( False )
- else:
- self.setMinimumHeight( 0 )
- self.setMaximumHeight( 1000000 )
- self.widget().setVisible( True )
- self._accordianWidget.emitItemCollapsed( self )
- accord.setUpdatesEnabled(True)
- def setCollapsible( self, state = True ):
- self._collapsible = state
- def setCustomData( self, key, value ):
- """
- \remarks set a custom pointer to information stored on this item
- \param key <str>
- \param value <variant>
- """
- self._customData[ str(key) ] = value
- def setDragDropMode( self, mode ):
- self._dragDropMode = mode
- def setRolloutStyle( self, style ):
- self._rolloutStyle = style
- def showMenu( self ):
- from PyQt4.QtCore import QRect
- from PyQt4.QtGui import QCursor
- if ( QRect( 0, 0, self.width(), 20 ).contains( self.mapFromGlobal( QCursor.pos() ) ) ):
- self._accordianWidget.emitItemMenuRequested( self )
- def rolloutStyle( self ):
- return self._rolloutStyle
- def toggleCollapsed( self ):
- self.setCollapsed( not self.isCollapsed() )
- def widget( self ):
- return self._widget
- ##
- # \namespace trax.gui.widgets.accordianwidget
- #
- # \remarks A container widget for creating expandable and collapsible components
- #
- # \author [email protected]
- # \author Blur Studio
- # \date 04/29/10
- #
- #
- from PyQt4.QtCore import pyqtSignal, pyqtProperty
- from PyQt4.QtGui import QScrollArea
- #from accordianitem import AccordianItem
- class AccordianWidget( QScrollArea ):
- itemCollapsed = pyqtSignal(AccordianItem)
- itemMenuRequested = pyqtSignal(AccordianItem)
- itemDragFailed = pyqtSignal(AccordianItem)
- itemsReordered = pyqtSignal()
- Boxed = 1
- Rounded = 2
- NoDragDrop = 0
- InternalMove = 1
- def __init__( self, parent ):
- QScrollArea.__init__( self, parent )
- self.setFrameShape( QScrollArea.NoFrame )
- self.setAutoFillBackground( False )
- self.setWidgetResizable( True )
- self.setMouseTracking(True)
- self.verticalScrollBar().setMaximumWidth(10)
- from PyQt4.QtGui import QWidget
- widget = QWidget( self )
- # define custom properties
- self._rolloutStyle = AccordianWidget.Rounded
- self._dragDropMode = AccordianWidget.NoDragDrop
- self._scrolling = False
- self._scrollInitY = 0
- self._scrollInitVal = 0
- self._itemClass = AccordianItem
- # create the layout
- from PyQt4.QtGui import QVBoxLayout
- layout = QVBoxLayout()
- layout.setContentsMargins( 3, 3, 3, 3 )
- layout.setSpacing( 3 )
- layout.addStretch(1)
- widget.setLayout( layout )
- self.setWidget( widget )
- def addItem( self, title, widget, collapsed = False ):
- self.setUpdatesEnabled(False)
- item = self._itemClass( self, title, widget )
- item.setRolloutStyle( self.rolloutStyle() )
- item.setDragDropMode( self.dragDropMode() )
- layout = self.widget().layout()
- layout.insertWidget( layout.count() - 1, item )
- layout.setStretchFactor( item, 0 )
- if ( collapsed ):
- item.setCollapsed(collapsed)
- self.setUpdatesEnabled(True)
- return item
- def clear( self ):
- self.setUpdatesEnabled(False)
- layout = self.widget().layout()
- while ( layout.count() > 1 ):
- item = layout.itemAt(0)
- # remove the item from the layout
- w = item.widget()
- layout.removeItem( item )
- # close the widget and delete it
- w.close()
- w.deleteLater()
- self.setUpdatesEnabled(True)
- def eventFilter( self, object, event ):
- from PyQt4.QtCore import QEvent
- if ( event.type() == QEvent.MouseButtonPress ):
- self.mousePressEvent( event )
- return True
- elif ( event.type() == QEvent.MouseMove ):
- self.mouseMoveEvent( event )
- return True
- elif ( event.type() == QEvent.MouseButtonRelease ):
- self.mouseReleaseEvent( event )
- return True
- return False
- def canScroll( self ):
- return self.verticalScrollBar().maximum() > 0
- def count( self ):
- return self.widget().layout().count() - 1
- def dragDropMode( self ):
- return self._dragDropMode
- def indexOf(self, widget):
- """
- \remarks Searches for widget(not including child layouts).
- Returns the index of widget, or -1 if widget is not found
- \return <int>
- """
- layout = self.widget().layout()
- for index in range(layout.count()):
- if layout.itemAt(index).widget().widget() == widget:
- return index
- return -1
- def isBoxedMode( self ):
- return self._rolloutStyle == AccordianWidget.Boxed
- def itemClass( self ):
- return self._itemClass
- def itemAt( self, index ):
- layout = self.widget().layout()
- if ( 0 <= index and index < layout.count() - 1 ):
- return layout.itemAt( index ).widget()
- return None
- def emitItemCollapsed( self, item ):
- if ( not self.signalsBlocked() ):
- self.itemCollapsed.emit(item)
- def emitItemDragFailed( self, item ):
- if ( not self.signalsBlocked() ):
- self.itemDragFailed.emit(item)
- def emitItemMenuRequested( self, item ):
- if ( not self.signalsBlocked() ):
- self.itemMenuRequested.emit(item)
- def emitItemsReordered( self ):
- if ( not self.signalsBlocked() ):
- self.itemsReordered.emit()
- def enterEvent( self, event ):
- if ( self.canScroll() ):
- from PyQt4.QtCore import Qt
- from PyQt4.QtGui import QApplication
- QApplication.setOverrideCursor( Qt.OpenHandCursor )
- def leaveEvent( self, event ):
- if ( self.canScroll() ):
- from PyQt4.QtGui import QApplication
- QApplication.restoreOverrideCursor()
- def mouseMoveEvent( self, event ):
- if ( self._scrolling ):
- sbar = self.verticalScrollBar()
- smax = sbar.maximum()
- # calculate the distance moved for the moust point
- dy = event.globalY() - self._scrollInitY
- # calculate the percentage that is of the scroll bar
- dval = smax * ( dy / float(sbar.height()) )
- # calculate the new value
- sbar.setValue( self._scrollInitVal - dval )
- event.accept()
- def mousePressEvent( self, event ):
- # handle a scroll event
- from PyQt4.QtCore import Qt
- from PyQt4.QtGui import QApplication
- if ( event.button() == Qt.LeftButton and self.canScroll() ):
- self._scrolling = True
- self._scrollInitY = event.globalY()
- self._scrollInitVal = self.verticalScrollBar().value()
- QApplication.setOverrideCursor( Qt.ClosedHandCursor )
- event.accept()
- def mouseReleaseEvent( self, event ):
- from PyQt4.QtCore import Qt
- from PyQt4.QtGui import QApplication
- if ( self._scrolling ):
- QApplication.restoreOverrideCursor()
- self._scrolling = False
- self._scrollInitY = 0
- self._scrollInitVal = 0
- event.accept()
- def moveItemDown(self, index):
- layout = self.widget().layout()
- if (layout.count() - 1) > (index + 1):
- widget = layout.takeAt(index).widget()
- layout.insertWidget(index + 1, widget)
- def moveItemUp(self, index):
- if index > 0:
- layout = self.widget().layout()
- widget = layout.takeAt(index).widget()
- layout.insertWidget(index - 1, widget)
- def setBoxedMode( self, state ):
- if ( state ):
- self._rolloutStyle = AccordianWidget.Boxed
- else:
- self._rolloutStyle = AccordianWidget.Rounded
- def setDragDropMode( self, dragDropMode ):
- self._dragDropMode = dragDropMode
- for item in self.findChildren( AccordianItem ):
- item.setDragDropMode( self._dragDropMode )
- def setItemClass( self, itemClass ):
- self._itemClass = itemClass
- def setRolloutStyle( self, rolloutStyle ):
- self._rolloutStyle = rolloutStyle
- for item in self.findChildren( AccordianItem ):
- item.setRolloutStyle( self._rolloutStyle )
- def rolloutStyle( self ):
- return self._rolloutStyle
- def takeAt( self, index ):
- self.setUpdatesEnabled(False)
- layout = self.widget().layout()
- widget = None
- if ( 0 <= index and index < layout.count() - 1 ):
- item = layout.itemAt(index)
- widget = item.widget()
- layout.removeItem(item)
- widget.close()
- self.setUpdatesEnabled(True)
- return widget
- def widgetAt( self, index ):
- item = self.itemAt( index )
- if ( item ):
- return item.widget()
- return None
- pyBoxedMode = pyqtProperty( 'bool', isBoxedMode, setBoxedMode )
- from PyQt4 import QtGui
- def demoGui(GroupBox):
- GroupBox.setFlat(True)
- verticalLayout = QtGui.QVBoxLayout(GroupBox)
- formLayout = QtGui.QFormLayout()
- formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
- monkey1Label = QtGui.QLabel(GroupBox)
- formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, monkey1Label)
- monkey1LineEdit = QtGui.QLineEdit(GroupBox)
- formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, monkey1LineEdit)
- monnkey2Label = QtGui.QLabel(GroupBox)
- formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, monnkey2Label)
- monkey3Label = QtGui.QLabel(GroupBox)
- formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, monkey3Label)
- happyCheckBoxLabel = QtGui.QLabel(GroupBox)
- formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, happyCheckBoxLabel)
- happyCheckBoxCheckBox = QtGui.QCheckBox(GroupBox)
- formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, happyCheckBoxCheckBox)
- comboBox = QtGui.QComboBox(GroupBox)
- comboBox.addItem('')
- comboBox.addItem('')
- comboBox.addItem('')
- comboBox.addItem('')
- formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, comboBox)
- spinBox = QtGui.QSpinBox(GroupBox)
- formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, spinBox)
- verticalLayout.addLayout(formLayout)
- GroupBox.setWindowTitle(QtGui.QApplication.translate("GroupBox", "GroupBox", None, QtGui.QApplication.UnicodeUTF8))
- monkey1Label.setText(QtGui.QApplication.translate("GroupBox", "Text", None, QtGui.QApplication.UnicodeUTF8))
- monnkey2Label.setText(QtGui.QApplication.translate("GroupBox", "Combo", None, QtGui.QApplication.UnicodeUTF8))
- monkey3Label.setText(QtGui.QApplication.translate("GroupBox", "Spin", None, QtGui.QApplication.UnicodeUTF8))
- happyCheckBoxLabel.setText(QtGui.QApplication.translate("GroupBox", "CheckBox", None, QtGui.QApplication.UnicodeUTF8))
- comboBox.setItemText(0, QtGui.QApplication.translate("GroupBox", "a", None, QtGui.QApplication.UnicodeUTF8))
- comboBox.setItemText(1, QtGui.QApplication.translate("GroupBox", "b", None, QtGui.QApplication.UnicodeUTF8))
- comboBox.setItemText(2, QtGui.QApplication.translate("GroupBox", "c", None, QtGui.QApplication.UnicodeUTF8))
- comboBox.setItemText(3, QtGui.QApplication.translate("GroupBox", "d", None, QtGui.QApplication.UnicodeUTF8))
- return GroupBox
- if __name__ == '__main__':
- from PyQt4.QtGui import QApplication
- app = QApplication([])
- #app.setStyle( 'Plastique' )
- dlg = AccordianWidget(None)
- dlg.addItem('a', demoGui(QtGui.QGroupBox()))
- dlg.addItem('b', demoGui(QtGui.QGroupBox()))
- dlg.addItem('c', demoGui(QtGui.QGroupBox()))
- dlg.show()
- app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement