class SearchLineEdit(QLineEdit): def __init__(self, parent = None): QLineEdit.__init__(self, parent) self.searchButton = QToolButton(self) self.searchButton.setCursor(QCursor()) self.searchButton.setIcon(QIcon("./img/search.svg")) frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth); self.searchButton.setStyleSheet("QToolButton {border: none; padding: 0px;}") self.setStyleSheet(QString( '''QLineEdit { padding-right: %1px; padding-left: 2px; padding-top: 1px; padding-bottom: 1px; } ''').arg(self.searchButton.sizeHint().width() + frameWidth + 1)); def resizeEvent(self, event = None): if event: QLineEdit.resizeEvent(self, event) sz = self.searchButton.sizeHint() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.searchButton.move(self.rect().right() - frameWidth - sz.width(), (self.rect().bottom() + 1 - sz.height())/2) def focusInEvent(self, event = None): QLineEdit.focusInEvent(self, event) self.emit(SIGNAL("focusChange()")) def focusOutEvent(self, event = None): QLineEdit.focusOutEvent(self, event) self.emit(SIGNAL("focusChange()"))
class HighlightEdit(QLineEdit): clicked = pyqtSignal(name="clicked") def __init__(self, parent): QLineEdit.__init__(self, parent) self._highlight_effect = QGraphicsDropShadowEffect(self) self._highlight_effect.setOffset(0.0) self._highlight_effect.setBlurRadius(5.0) self._highlight_effect.setColor(QColor(50, 50, 200)) self.setGraphicsEffect(self._highlight_effect) self._highlight_effect.setEnabled(False) self.clear_button = QToolButton(self) self.clear_button.setIcon(QIcon.fromTheme("edit-clear", QIcon("icons/delete_icon.png"))) self.clear_button.setCursor(Qt.ArrowCursor) self.clear_button.setStyleSheet("QToolButton { border: none; padding: 1.5px; }") icon_size = int(self.sizeHint().height() * 0.65) self.clear_button.setIconSize(QSize(icon_size, icon_size)) self.clear_button.clicked.connect(self.clear) # self.clear_button.hide() # some padding stuff frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet( "QLineEdit {{ padding-right: {}px; }} ".format(self.clear_button.sizeHint().width() + frameWidth) ) # create a signal on doubleclick events def mouseDoubleClickEvent(self, ev): ev.accept() self.clicked.emit() # fix up the clear button positioning def resizeEvent(self, ev): sz = self.clear_button.sizeHint() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.clear_button.move( self.rect().right() - frameWidth - sz.width(), (self.rect().bottom() + 1 - sz.height()) / 2 ) # a slot for turning the graphics effect on and off @pyqtSlot(bool) def highlight(self, val): self._highlight_effect.setEnabled(val)
class HighlightEdit(QLineEdit): clicked = pyqtSignal(name='clicked') def __init__(self, parent): QLineEdit.__init__(self, parent) self._highlight_effect = QGraphicsDropShadowEffect(self) self._highlight_effect.setOffset(0.0) self._highlight_effect.setBlurRadius(5.0) self._highlight_effect.setColor(QColor(50, 50, 200)) self.setGraphicsEffect(self._highlight_effect) self._highlight_effect.setEnabled(False) self.clear_button = QToolButton(self) self.clear_button.setIcon( QIcon.fromTheme("edit-clear", QIcon("icons/delete_icon.png"))) self.clear_button.setCursor(Qt.ArrowCursor) self.clear_button.setStyleSheet( "QToolButton { border: none; padding: 1.5px; }") icon_size = int(self.sizeHint().height() * 0.65) self.clear_button.setIconSize(QSize(icon_size, icon_size)) self.clear_button.clicked.connect(self.clear) #self.clear_button.hide() # some padding stuff frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet("QLineEdit {{ padding-right: {}px; }} ".format( self.clear_button.sizeHint().width() + frameWidth)) #create a signal on doubleclick events def mouseDoubleClickEvent(self, ev): ev.accept() self.clicked.emit() # fix up the clear button positioning def resizeEvent(self, ev): sz = self.clear_button.sizeHint() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.clear_button.move(self.rect().right() - frameWidth - sz.width(), (self.rect().bottom() + 1 - sz.height()) / 2) # a slot for turning the graphics effect on and off @pyqtSlot(bool) def highlight(self, val): self._highlight_effect.setEnabled(val)
def rebuildButtons( self ): """ Rebuilds the buttons for the advanced actions. """ for btn in self.findChildren(QToolButton): btn.close() btn.setParent(None) btn.deleteLater() for standard, advanced in self._advancedMap.items(): rect = self.actionGeometry(standard) btn = QToolButton(self) btn.setFixedWidth(22) btn.setFixedHeight(rect.height()) btn.setDefaultAction(advanced) btn.setAutoRaise(True) btn.move(rect.right() + 1, rect.top()) if btn.icon().isNull(): btn.setIcon(QIcon(resources.find('img/advanced.png'))) btn.clicked.connect(self.acceptAdvanced)
class IconLineEdit(QLineEdit): def __init__(self, parent=None): QLineEdit.__init__(self, parent) self.setPlaceholderText(self.tr('Email')) self.btnIcon = QToolButton(self) self.btnIcon.setIcon(QIcon(os.path.join(pluginPath, 'icons', 'envelope.svg'))) self.btnIcon.setEnabled(False) self.btnIcon.setStyleSheet('QToolButton { border: none; padding: 0px; }') frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet('QLineEdit {{ padding-left: {}px; }} '.format(self.btnIcon.sizeHint().width() + frameWidth + 1)) msz = self.minimumSizeHint() self.setMinimumSize(max(msz.width(), self.btnIcon.sizeHint().height() + frameWidth * 2 + 2), max(msz.height(), self.btnIcon.sizeHint().height() + frameWidth * 2 + 2)) def resizeEvent(self, event): frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) sz = self.btnIcon.sizeHint() self.btnIcon.move(frameWidth + 1, (self.rect().bottom() + 1 - sz.height()) / 2)
class Search_QLineEdit(QLineEdit): """ Defines a `QLineEdit <http://doc.qt.nokia.com/qlinedit.html>`_ subclass providing a search field with clearing capabilities. """ def __init__( self, parent=None, uiSearchImage=None, uiSearchClickedImage=None, uiClearImage=None, uiClearClickedImage=None ): """ Initializes the class. :param parent: Widget parent. :type parent: QObject :param uiSearchImage: Search button image path. :type uiSearchImage: str :param uiSearchClickedImage: Search button clicked image path. :type uiSearchClickedImage: str :param uiClearImage: Clear button image path. :type uiClearImage: str :param uiClearClickedImage: Clear button clicked image path. :type uiClearClickedImage: str """ LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__)) QLineEdit.__init__(self, parent) # --- Setting class attributes. --- self.__uiSearchImage = None self.uiSearchImage = uiSearchImage or umbra.ui.common.getResourcePath("images/Search_Glass.png") self.__uiSearchClickedImage = None self.uiSearchClickedImage = uiSearchClickedImage or umbra.ui.common.getResourcePath( "images/Search_Glass_Clicked.png" ) self.__uiClearImage = None self.uiClearImage = uiClearImage or umbra.ui.common.getResourcePath("images/Search_Clear.png") self.__uiClearClickedImage = None self.uiClearClickedImage = uiClearClickedImage or umbra.ui.common.getResourcePath( "images/Search_Clear_Clicked.png" ) self.__searchActiveLabel = Active_QLabel( self, QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchClickedImage) ) self.__searchActiveLabel.setObjectName("Search_Field_activeLabel") self.__searchActiveLabel.showEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.showEvent(self.__searchActiveLabel, event)) ) self.__searchActiveLabel.hideEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.hideEvent(self.__searchActiveLabel, event)) ) self.__clearButton = QToolButton(self) self.__clearButton.setObjectName("Clear_Field_button") self.__completer = QCompleter() self.setCompleter(self.__completer) self.__completerVisibleItemsCount = 16 Search_QLineEdit.__initializeUi(self) self.__setClearButtonVisibility(self.text()) # Signals / Slots. self.__clearButton.clicked.connect(self.clear) self.textChanged.connect(self.__setClearButtonVisibility) # ****************************************************************************************************************** # *** Attributes properties. # ****************************************************************************************************************** @property def uiSearchImage(self): """ Property for **self.__uiSearchImage** attribute. :return: self.__uiSearchImage. :rtype: str """ return self.__uiSearchImage @uiSearchImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchImage(self, value): """ Setter for **self.__uiSearchImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchImage", value ) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format("uiSearchImage", value) self.__uiSearchImage = value @uiSearchImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiSearchImage(self): """ Deleter for **self.__uiSearchImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchImage") ) @property def uiSearchClickedImage(self): """ Property for **self.__uiSearchClickedImage** attribute. :return: self.__uiSearchClickedImage. :rtype: str """ return self.__uiSearchClickedImage @uiSearchClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchClickedImage(self, value): """ Setter for **self.__uiSearchClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchClickedImage", value ) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchClickedImage", value ) self.__uiSearchClickedImage = value @uiSearchClickedImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiSearchClickedImage(self): """ Deleter for **self.__uiSearchClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchClickedImage") ) @property def uiClearImage(self): """ Property for **self.__uiClearImage** attribute. :return: self.__uiClearImage. :rtype: str """ return self.__uiClearImage @uiClearImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearImage(self, value): """ Setter for **self.__uiClearImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format("uiClearImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format("uiClearImage", value) self.__uiClearImage = value @uiClearImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiClearImage(self): """ Deleter for **self.__uiClearImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearImage") ) @property def uiClearClickedImage(self): """ Property for **self.__uiClearClickedImage** attribute. :return: self.__uiClearClickedImage. :rtype: str """ return self.__uiClearClickedImage @uiClearClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearClickedImage(self, value): """ Setter for **self.__uiClearClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiClearClickedImage", value ) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearClickedImage", value ) self.__uiClearClickedImage = value @uiClearClickedImage.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def uiClearClickedImage(self): """ Deleter for **self.__uiClearClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearClickedImage") ) @property def searchActiveLabel(self): """ Property for **self.__searchActiveLabel** attribute. :return: self.__searchActiveLabel. :rtype: QPushButton """ return self.__searchActiveLabel @searchActiveLabel.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def searchActiveLabel(self, value): """ Setter for **self.__searchActiveLabel** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "searchActiveLabel") ) @searchActiveLabel.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def searchActiveLabel(self): """ Deleter for **self.__searchActiveLabel** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "searchActiveLabel") ) @property def clearButton(self): """ Property for **self.__clearButton** attribute. :return: self.__clearButton. :rtype: QPushButton """ return self.__clearButton @clearButton.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def clearButton(self, value): """ Setter for **self.__clearButton** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "clearButton") ) @clearButton.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def clearButton(self): """ Deleter for **self.__clearButton** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "clearButton") ) @property def completer(self): """ Property for **self.__completer** attribute. :return: self.__completer. :rtype: QCompleter """ return self.__completer @completer.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completer(self, value): """ Setter for **self.__completer** attribute. :param value: Attribute value. :type value: QCompleter """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completer") ) @completer.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completer(self): """ Deleter for **self.__completer** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completer") ) @property def completerVisibleItemsCount(self): """ Property for **self.__completerVisibleItemsCount** attribute. :return: self.__completerVisibleItemsCount. :rtype: int """ return self.__completerVisibleItemsCount @completerVisibleItemsCount.setter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self, value): """ Setter for **self.__completerVisibleItemsCount** attribute. :param value: Attribute value. :type value: int """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completerVisibleItemsCount") ) @completerVisibleItemsCount.deleter @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self): """ Deleter for **self.__completerVisibleItemsCount** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completerVisibleItemsCount") ) # ****************************************************************************************************************** # *** Class methods. # ****************************************************************************************************************** def resizeEvent(self, event): """ Reimplements the :meth:`QLineEdit.QResizeEvent` method. :param event: Resize event. :type event: QResizeEvent """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) searchActiveLabelSize = self.__searchActiveLabel.sizeHint() self.__searchActiveLabel.move( self.rect().left() + frameWidth, (self.rect().bottom() - searchActiveLabelSize.height()) / 2 + frameWidth / 2, ) clearButtonSize = self.__clearButton.sizeHint() self.__clearButton.move( self.rect().right() - frameWidth - clearButtonSize.width(), (self.rect().bottom() - clearButtonSize.height()) / 2 + frameWidth / 2, ) def __initializeUi(self): """ Initializes the Widget ui. """ self.__clearButton.setCursor(Qt.ArrowCursor) if self.__uiClearImage and self.__uiClearClickedImage: pixmap = QPixmap(self.__uiClearImage) clickedPixmap = QPixmap(self.__uiClearClickedImage) self.__clearButton.setIcon(QIcon(pixmap)) self.__clearButton.setMaximumSize(pixmap.size()) # Signals / Slots. self.__clearButton.pressed.connect(functools.partial(self.__clearButton.setIcon, QIcon(clickedPixmap))) self.__clearButton.released.connect(functools.partial(self.__clearButton.setIcon, QIcon(pixmap))) else: self.__clearButton.setText("Clear") self.__setStyleSheet() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setMinimumSize( max(self.minimumSizeHint().width(), self.__clearButton.sizeHint().height() + frameWidth * 2), max(self.minimumSizeHint().height(), self.__clearButton.sizeHint().height() + frameWidth * 2), ) self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) # self.__completer.setMaxVisibleItems(self.__completerVisibleItemsCount) def __setStyleSheet(self): """ Sets the Widget stylesheet. """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet( QString( "QLineEdit {{ padding-left: {0}px; padding-right: {1}px; }}\nQToolButton {{ border: none; padding: 0px; }}".format( self.__searchActiveLabel.sizeHint().width() if self.__searchActiveLabel.isVisible() else 0 + frameWidth, self.__clearButton.sizeHint().width() + frameWidth, ) ) ) def __setClearButtonVisibility(self, text): """ Sets the clear button visibility. :param text: Current field text. :type text: QString """ if text: self.__clearButton.show() else: self.__clearButton.hide()
class LineEdit(QLineEdit): """Extended QLineEdit. Supports prompt and Clear button """ clearButtonClicked = pyqtSignal() """ clearButtonClicked() **Signal** emitted, when Clear button has been clicked """ def __init__(self, parent): QLineEdit.__init__(self, parent) self._margin = self.sizeHint().height() -2 self._spacing = 0 self._tbClear = QToolButton( self ) self._tbClear.setIcon( QIcon(":enkiicons/fresh/edit-clear-rtl.png")) self._tbClear.setToolTip( tr( "Clear" ) ) self._tbClear.setStyleSheet( "QToolButton { border: none; padding: 0px; }" ) self._tbClear.setCursor( Qt.ArrowCursor ) self._tbClear.setFocusPolicy( Qt.NoFocus ) self.setClearButtonVisible( False ) self.textChanged.connect(self._onTextChanged) self._tbClear.clicked.connect(self.clear) self._tbClear.clicked.connect(self.clearButtonClicked) def promptText(self): """Current prompt text """ return self._promptText def setPromptText(self, prompt ): """Set prompt text """ self._promptText = prompt self.update() def paintEvent(self, event ): """QLineEdit.paintEvent implementation. Draws prompt """ QLineEdit.paintEvent( self, event ) if self._promptText and not self.text() and self.isEnabled() : option = QStyleOptionFrameV3() self.initStyleOption( option ) left, top, right, bottom = self.getTextMargins() va = self.style().visualAlignment( self.layoutDirection(), self.alignment() ) rect = self.style().subElementRect( QStyle.SE_LineEditContents, option, self ).adjusted( 2, 0, 0, 0 ).adjusted( left, top, -right, -bottom ) fm = QFontMetrics ( self.font() ) text = fm.elidedText( self._promptText, Qt.ElideRight, rect.width() ) painter = QPainter ( self ) painter.setPen( self.palette().color( QPalette.Disabled, QPalette.Text ) ) painter.drawText( rect, va, text ) def resizeEvent(self, event ): """QLineEdit.resizeEvent implementation Adjusts Clear button position """ QLineEdit.resizeEvent( self, event ) self._tbClear.resize( QSize( self._margin, self.height() -2 ) ) self._tbClear.move( self.width() -self._margin -3, 0 ) def setClearButtonVisible(self, visible ): """Set Clear button visible """ self._tbClear.setVisible( visible ) left, top, right, bottom = self.getTextMargins() if visible : right = self._margin +self._spacing else: right = 0 self.setTextMargins( left, top, right, bottom ) def _onTextChanged(self, text ): """Text changed, update Clear button visibility """ self.setClearButtonVisible( len(text) > 0 )
class Search_QLineEdit(QLineEdit): """ Defines a `QLineEdit <http://doc.qt.nokia.com/qlinedit.html>`_ subclass providing a search field with clearing capabilities. """ def __init__(self, parent=None, uiSearchImage=None, uiSearchClickedImage=None, uiClearImage=None, uiClearClickedImage=None): """ Initializes the class. :param parent: Widget parent. :type parent: QObject :param uiSearchImage: Search button image path. :type uiSearchImage: str :param uiSearchClickedImage: Search button clicked image path. :type uiSearchClickedImage: str :param uiClearImage: Clear button image path. :type uiClearImage: str :param uiClearClickedImage: Clear button clicked image path. :type uiClearClickedImage: str """ LOGGER.debug("> Initializing '{0}()' class.".format( self.__class__.__name__)) QLineEdit.__init__(self, parent) # --- Setting class attributes. --- self.__uiSearchImage = None self.uiSearchImage = uiSearchImage or umbra.ui.common.getResourcePath( "images/Search_Glass.png") self.__uiSearchClickedImage = None self.uiSearchClickedImage = uiSearchClickedImage or umbra.ui.common.getResourcePath( "images/Search_Glass_Clicked.png") self.__uiClearImage = None self.uiClearImage = uiClearImage or umbra.ui.common.getResourcePath( "images/Search_Clear.png") self.__uiClearClickedImage = None self.uiClearClickedImage = uiClearClickedImage or umbra.ui.common.getResourcePath( "images/Search_Clear_Clicked.png") self.__searchActiveLabel = Active_QLabel( self, QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchClickedImage)) self.__searchActiveLabel.setObjectName("Search_Field_activeLabel") self.__searchActiveLabel.showEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.showEvent(self.__searchActiveLabel, event))) self.__searchActiveLabel.hideEvent = lambda event: reduce( lambda *args: None, (self.__setStyleSheet(), Active_QLabel.hideEvent(self.__searchActiveLabel, event))) self.__clearButton = QToolButton(self) self.__clearButton.setObjectName("Clear_Field_button") self.__completer = QCompleter() self.setCompleter(self.__completer) self.__completerVisibleItemsCount = 16 Search_QLineEdit.__initializeUi(self) self.__setClearButtonVisibility(self.text()) # Signals / Slots. self.__clearButton.clicked.connect(self.clear) self.textChanged.connect(self.__setClearButtonVisibility) #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def uiSearchImage(self): """ Property for **self.__uiSearchImage** attribute. :return: self.__uiSearchImage. :rtype: str """ return self.__uiSearchImage @uiSearchImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchImage(self, value): """ Setter for **self.__uiSearchImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchImage", value) self.__uiSearchImage = value @uiSearchImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiSearchImage(self): """ Deleter for **self.__uiSearchImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiSearchImage")) @property def uiSearchClickedImage(self): """ Property for **self.__uiSearchClickedImage** attribute. :return: self.__uiSearchClickedImage. :rtype: str """ return self.__uiSearchClickedImage @uiSearchClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiSearchClickedImage(self, value): """ Setter for **self.__uiSearchClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiSearchClickedImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchClickedImage", value) self.__uiSearchClickedImage = value @uiSearchClickedImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiSearchClickedImage(self): """ Deleter for **self.__uiSearchClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiSearchClickedImage")) @property def uiClearImage(self): """ Property for **self.__uiClearImage** attribute. :return: self.__uiClearImage. :rtype: str """ return self.__uiClearImage @uiClearImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearImage(self, value): """ Setter for **self.__uiClearImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiClearImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearImage", value) self.__uiClearImage = value @uiClearImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiClearImage(self): """ Deleter for **self.__uiClearImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiClearImage")) @property def uiClearClickedImage(self): """ Property for **self.__uiClearClickedImage** attribute. :return: self.__uiClearClickedImage. :rtype: str """ return self.__uiClearClickedImage @uiClearClickedImage.setter @foundations.exceptions.handleExceptions(AssertionError) def uiClearClickedImage(self, value): """ Setter for **self.__uiClearClickedImage** attribute. :param value: Attribute value. :type value: str """ if value is not None: assert type( value ) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format( "uiClearClickedImage", value) assert os.path.exists( value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearClickedImage", value) self.__uiClearClickedImage = value @uiClearClickedImage.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def uiClearClickedImage(self): """ Deleter for **self.__uiClearClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "uiClearClickedImage")) @property def searchActiveLabel(self): """ Property for **self.__searchActiveLabel** attribute. :return: self.__searchActiveLabel. :rtype: QPushButton """ return self.__searchActiveLabel @searchActiveLabel.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def searchActiveLabel(self, value): """ Setter for **self.__searchActiveLabel** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "searchActiveLabel")) @searchActiveLabel.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def searchActiveLabel(self): """ Deleter for **self.__searchActiveLabel** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "searchActiveLabel")) @property def clearButton(self): """ Property for **self.__clearButton** attribute. :return: self.__clearButton. :rtype: QPushButton """ return self.__clearButton @clearButton.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def clearButton(self, value): """ Setter for **self.__clearButton** attribute. :param value: Attribute value. :type value: QPushButton """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "clearButton")) @clearButton.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def clearButton(self): """ Deleter for **self.__clearButton** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "clearButton")) @property def completer(self): """ Property for **self.__completer** attribute. :return: self.__completer. :rtype: QCompleter """ return self.__completer @completer.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completer(self, value): """ Setter for **self.__completer** attribute. :param value: Attribute value. :type value: QCompleter """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "completer")) @completer.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completer(self): """ Deleter for **self.__completer** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "completer")) @property def completerVisibleItemsCount(self): """ Property for **self.__completerVisibleItemsCount** attribute. :return: self.__completerVisibleItemsCount. :rtype: int """ return self.__completerVisibleItemsCount @completerVisibleItemsCount.setter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self, value): """ Setter for **self.__completerVisibleItemsCount** attribute. :param value: Attribute value. :type value: int """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format( self.__class__.__name__, "completerVisibleItemsCount")) @completerVisibleItemsCount.deleter @foundations.exceptions.handleExceptions( foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self): """ Deleter for **self.__completerVisibleItemsCount** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format( self.__class__.__name__, "completerVisibleItemsCount")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** def resizeEvent(self, event): """ Reimplements the :meth:`QLineEdit.QResizeEvent` method. :param event: Resize event. :type event: QResizeEvent """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) searchActiveLabelSize = self.__searchActiveLabel.sizeHint() self.__searchActiveLabel.move( self.rect().left() + frameWidth, (self.rect().bottom() - searchActiveLabelSize.height()) / 2 + frameWidth / 2) clearButtonSize = self.__clearButton.sizeHint() self.__clearButton.move( self.rect().right() - frameWidth - clearButtonSize.width(), (self.rect().bottom() - clearButtonSize.height()) / 2 + frameWidth / 2) def __initializeUi(self): """ Initializes the Widget ui. """ self.__clearButton.setCursor(Qt.ArrowCursor) if self.__uiClearImage and self.__uiClearClickedImage: pixmap = QPixmap(self.__uiClearImage) clickedPixmap = QPixmap(self.__uiClearClickedImage) self.__clearButton.setIcon(QIcon(pixmap)) self.__clearButton.setMaximumSize(pixmap.size()) # Signals / Slots. self.__clearButton.pressed.connect( functools.partial(self.__clearButton.setIcon, QIcon(clickedPixmap))) self.__clearButton.released.connect( functools.partial(self.__clearButton.setIcon, QIcon(pixmap))) else: self.__clearButton.setText("Clear") self.__setStyleSheet() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setMinimumSize( max(self.minimumSizeHint().width(), self.__clearButton.sizeHint().height() + frameWidth * 2), max(self.minimumSizeHint().height(), self.__clearButton.sizeHint().height() + frameWidth * 2)) self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setCompletionMode( QCompleter.UnfilteredPopupCompletion) # self.__completer.setMaxVisibleItems(self.__completerVisibleItemsCount) def __setStyleSheet(self): """ Sets the Widget stylesheet. """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet( QString( "QLineEdit {{ padding-left: {0}px; padding-right: {1}px; }}\nQToolButton {{ border: none; padding: 0px; }}" .format( self.__searchActiveLabel.sizeHint().width() if self.__searchActiveLabel.isVisible() else 0 + frameWidth, self.__clearButton.sizeHint().width() + frameWidth))) def __setClearButtonVisibility(self, text): """ Sets the clear button visibility. :param text: Current field text. :type text: QString """ if text: self.__clearButton.show() else: self.__clearButton.hide()
class Search_QLineEdit(QLineEdit): """ This class is a `QLineEdit <http://doc.qt.nokia.com/qlinedit.html>`_ subclass providing a search field with clearing capabilities. """ @core.executionTrace def __init__(self, parent=None, uiSearchImage=None, uiSearchClickedImage=None, uiClearImage=None, uiClearClickedImage=None): """ This method initializes the class. :param parent: Widget parent. ( QObject ) :param uiSearchImage: Search button image path. ( String ) :param uiSearchClickedImage: Search button clicked image path. ( String ) :param uiClearImage: Clear button image path. ( String ) :param uiClearClickedImage: Clear button clicked image path. ( String ) """ LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__)) QLineEdit.__init__(self, parent) # --- Setting class attributes. --- self.__uiSearchImage = None self.uiSearchImage = uiSearchImage or snippets.ui.common.getResourcePath("images/Search_Glass.png") self.__uiSearchClickedImage = None self.uiSearchClickedImage = uiSearchClickedImage or snippets.ui.common.getResourcePath( "images/Search_Glass_Clicked.png") self.__uiClearImage = None self.uiClearImage = uiClearImage or snippets.ui.common.getResourcePath("images/Search_Clear.png") self.__uiClearClickedImage = None self.uiClearClickedImage = uiClearClickedImage or snippets.ui.common.getResourcePath( "images/Search_Clear_Clicked.png") self.__searchActiveLabel = Active_QLabel(self, QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchImage), QPixmap(self.__uiSearchClickedImage)) self.__searchActiveLabel.setObjectName("Search_Field_activeLabel") self.__clearButton = QToolButton(self) self.__clearButton.setObjectName("Clear_Field_button") self.__completer = QCompleter() self.setCompleter(self.__completer) self.__completerVisibleItemsCount = 16 # TODO: Rollback to Search_QLineEdit.__initializeUi(self) whenever MPC changes it's PyQt version. self.__initializeUi() self.__setClearButtonVisibility(self.text()) # Signals / Slots. self.__clearButton.clicked.connect(self.clear) self.textChanged.connect(self.__setClearButtonVisibility) #****************************************************************************************************************** #*** Attributes properties. #****************************************************************************************************************** @property def uiSearchImage(self): """ This method is the property for **self.__uiSearchImage** attribute. :return: self.__uiSearchImage. ( String ) """ return self.__uiSearchImage @uiSearchImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiSearchImage(self, value): """ This method is the setter method for **self.__uiSearchImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiSearchImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format("uiSearchImage", value) self.__uiSearchImage = value @uiSearchImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiSearchImage(self): """ This method is the deleter method for **self.__uiSearchImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchImage")) @property def uiSearchClickedImage(self): """ This method is the property for **self.__uiSearchClickedImage** attribute. :return: self.__uiSearchClickedImage. ( String ) """ return self.__uiSearchClickedImage @uiSearchClickedImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiSearchClickedImage(self, value): """ This method is the setter method for **self.__uiSearchClickedImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiSearchClickedImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiSearchClickedImage", value) self.__uiSearchClickedImage = value @uiSearchClickedImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiSearchClickedImage(self): """ This method is the deleter method for **self.__uiSearchClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiSearchClickedImage")) @property def uiClearImage(self): """ This method is the property for **self.__uiClearImage** attribute. :return: self.__uiClearImage. ( String ) """ return self.__uiClearImage @uiClearImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiClearImage(self, value): """ This method is the setter method for **self.__uiClearImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiClearImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearImage", value) self.__uiClearImage = value @uiClearImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiClearImage(self): """ This method is the deleter method for **self.__uiClearImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearImage")) @property def uiClearClickedImage(self): """ This method is the property for **self.__uiClearClickedImage** attribute. :return: self.__uiClearClickedImage. ( String ) """ return self.__uiClearClickedImage @uiClearClickedImage.setter @foundations.exceptions.exceptionsHandler(None, False, AssertionError) def uiClearClickedImage(self, value): """ This method is the setter method for **self.__uiClearClickedImage** attribute. :param value: Attribute value. ( String ) """ if value is not None: assert type(value) in (str, unicode), "'{0}' attribute: '{1}' type is not 'str' or 'unicode'!".format( "uiClearClickedImage", value) assert os.path.exists(value), "'{0}' attribute: '{1}' file doesn't exists!".format( "uiClearClickedImage", value) self.__uiClearClickedImage = value @uiClearClickedImage.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def uiClearClickedImage(self): """ This method is the deleter method for **self.__uiClearClickedImage** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "uiClearClickedImage")) @property def searchActiveLabel(self): """ This method is the property for **self.__searchActiveLabel** attribute. :return: self.__searchActiveLabel. ( QPushButton ) """ return self.__searchActiveLabel @searchActiveLabel.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def searchActiveLabel(self, value): """ This method is the setter method for **self.__searchActiveLabel** attribute. :param value: Attribute value. ( QPushButton ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "searchActiveLabel")) @searchActiveLabel.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def searchActiveLabel(self): """ This method is the deleter method for **self.__searchActiveLabel** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "searchActiveLabel")) @property def clearButton(self): """ This method is the property for **self.__clearButton** attribute. :return: self.__clearButton. ( QPushButton ) """ return self.__clearButton @clearButton.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def clearButton(self, value): """ This method is the setter method for **self.__clearButton** attribute. :param value: Attribute value. ( QPushButton ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "clearButton")) @clearButton.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def clearButton(self): """ This method is the deleter method for **self.__clearButton** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "clearButton")) @property def completer(self): """ This method is the property for **self.__completer** attribute. :return: self.__completer. ( QCompleter ) """ return self.__completer @completer.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completer(self, value): """ This method is the setter method for **self.__completer** attribute. :param value: Attribute value. ( QCompleter ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completer")) @completer.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completer(self): """ This method is the deleter method for **self.__completer** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completer")) @property def completerVisibleItemsCount(self): """ This method is the property for **self.__completerVisibleItemsCount** attribute. :return: self.__completerVisibleItemsCount. ( Integer ) """ return self.__completerVisibleItemsCount @completerVisibleItemsCount.setter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self, value): """ This method is the setter method for **self.__completerVisibleItemsCount** attribute. :param value: Attribute value. ( Integer ) """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "completerVisibleItemsCount")) @completerVisibleItemsCount.deleter @foundations.exceptions.exceptionsHandler(None, False, foundations.exceptions.ProgrammingError) def completerVisibleItemsCount(self): """ This method is the deleter method for **self.__completerVisibleItemsCount** attribute. """ raise foundations.exceptions.ProgrammingError( "{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "completerVisibleItemsCount")) #****************************************************************************************************************** #*** Class methods. #****************************************************************************************************************** @core.executionTrace def resizeEvent(self, event): """ This method reimplements the :meth:`QLineEdit.QResizeEvent` method. :param event: Resize event. ( QResizeEvent ) """ frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) searchActiveLabelSize = self.__searchActiveLabel.sizeHint() self.__searchActiveLabel.move(self.rect().left() + frameWidth, (self.rect().bottom() - searchActiveLabelSize.height()) / 2 + frameWidth / 2) clearButtonSize = self.__clearButton.sizeHint() self.__clearButton.move(self.rect().right() - frameWidth - clearButtonSize.width(), (self.rect().bottom() - clearButtonSize.height()) / 2 + frameWidth / 2) @core.executionTrace def __initializeUi(self): """ This method initializes the Widget ui. """ self.__clearButton.setCursor(Qt.ArrowCursor) if self.__uiClearImage and self.__uiClearClickedImage: pixmap = QPixmap(self.__uiClearImage) clickedPixmap = QPixmap(self.__uiClearClickedImage) self.__clearButton.setStyleSheet("QToolButton { border: none; padding: 0px; }") self.__clearButton.setIcon(QIcon(pixmap)) self.__clearButton.setMaximumSize(pixmap.size()) # Signals / Slots. self.__clearButton.pressed.connect(functools.partial(self.__clearButton.setIcon, QIcon(clickedPixmap))) self.__clearButton.released.connect(functools.partial(self.__clearButton.setIcon, QIcon(pixmap))) else: self.__clearButton.setText("Clear") frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.setStyleSheet(QString("QLineEdit {{ padding-left: {0}px; padding-right: {1}px; }}".format( self.__searchActiveLabel.sizeHint().width() + frameWidth, self.__clearButton.sizeHint().width() + frameWidth))) self.setMinimumSize(max(self.minimumSizeHint().width(), self.__clearButton.sizeHint().height() + frameWidth * 2), max(self.minimumSizeHint().height(), self.__clearButton.sizeHint().height() + frameWidth * 2)) self.__completer.setCaseSensitivity(Qt.CaseInsensitive) self.__completer.setCompletionMode(QCompleter.PopupCompletion) # TODO: Restore next line whnever MPC changes it's PyQt version. # self.__completer.setMaxVisibleItems(self.__completerVisibleItemsCount) @core.executionTrace def __setClearButtonVisibility(self, text): """ This method sets the clear button visibility. :param text: Current field text. ( QString ) """ if text: self.__clearButton.show() else: self.__clearButton.hide()
class LineEdit(QLineEdit): """Extended QLineEdit. Supports prompt and Clear button """ clearButtonClicked = pyqtSignal() """ clearButtonClicked() **Signal** emitted, when Clear button has been clicked """ def __init__(self, parent): QLineEdit.__init__(self, parent) self._margin = self.sizeHint().height() - 2 self._spacing = 0 self._tbClear = QToolButton(self) self._tbClear.setIcon(QIcon(":enkiicons/edit-clear-rtl.png")) self._tbClear.setToolTip(tr("Clear")) self._tbClear.setStyleSheet( "QToolButton { border: none; padding: 0px; }") self._tbClear.setCursor(Qt.ArrowCursor) self._tbClear.setFocusPolicy(Qt.NoFocus) self.setClearButtonVisible(False) self.textChanged.connect(self._onTextChanged) self._tbClear.clicked.connect(self.clear) self._tbClear.clicked.connect(self.clearButtonClicked) def promptText(self): """Current prompt text """ return self._promptText def setPromptText(self, prompt): """Set prompt text """ self._promptText = prompt self.update() def paintEvent(self, event): """QLineEdit.paintEvent implementation. Draws prompt """ QLineEdit.paintEvent(self, event) if self._promptText and not self.text() and self.isEnabled(): option = QStyleOptionFrameV3() self.initStyleOption(option) left, top, right, bottom = self.getTextMargins() va = self.style().visualAlignment(self.layoutDirection(), self.alignment()) rect = self.style().subElementRect( QStyle.SE_LineEditContents, option, self).adjusted(2, 0, 0, 0).adjusted(left, top, -right, -bottom) fm = QFontMetrics(self.font()) text = fm.elidedText(self._promptText, Qt.ElideRight, rect.width()) painter = QPainter(self) painter.setPen(self.palette().color(QPalette.Disabled, QPalette.Text)) painter.drawText(rect, va, text) def resizeEvent(self, event): """QLineEdit.resizeEvent implementation Adjusts Clear button position """ QLineEdit.resizeEvent(self, event) self._tbClear.resize(QSize(self._margin, self.height() - 2)) self._tbClear.move(self.width() - self._margin - 3, 0) def setClearButtonVisible(self, visible): """Set Clear button visible """ self._tbClear.setVisible(visible) left, top, right, bottom = self.getTextMargins() if visible: right = self._margin + self._spacing else: right = 0 self.setTextMargins(left, top, right, bottom) def _onTextChanged(self, text): """Text changed, update Clear button visibility """ self.setClearButtonVisible(len(text) > 0)