AttributeError: 'Data' object has no attribute 'dragPosition' Python

0

I have the following problem, I have the following piece of code that I use to be able to move the MainWindow.

def mousePressEvent(self,event):
    if event.button() == QtCore.Qt.LeftButton:
        self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
        event.accept()
def mouseMoveEvent(self,event):
    if event.buttons() == QtCore.Qt.LeftButton:
        self.move(event.globalPos()-self.dragPosition)
        event.accept()

however when executing the program, only when clicking on QComboBox , it throws 2 errors,

1.- The first one is that if I move the mouse by very minimum when I click on the QComboBox , it throws me the following error:

Traceback (most recent call last):
      File "C:\Users\Angel\Desktop\Test\Login.py", line 87, in mouseMoveEvent
        self.move(event.globalPos()-self.dragPosition)
    AttributeError: 'Dato' object has no attribute 'dragPosition'
    [Finished in 28.2s with exit code 3]

2.- When I try to click again on the QComboBox it changes places:

I leave a gif with the 2 problems it generates ...

this is the complete code of the application:

from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5 import uic, QtCore, Qt
from Inicio import Inicio
from Firebase_load import *
from Registro import Image
from add_users import Usuarios
from es import user_name_1

class Principal(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi("Login.ui",self)
        self._Inicio = Inicio()
        self.registro = Image()
        self.add = Usuarios()

        self.combo_login ########## Este es el nombre de el QComboBox            

        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground,True)
        self.setAttribute(QtCore.Qt.WA_NoSystemBackground,False)

        self.closed.clicked.connect(lambda:self.close())
        self.mostrar_hora()

        self.timer = QtCore.QTimer(self)
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.mostrar_hora)
        self.timer.start()

    def mostrar_hora(self):
        self.hora.setText(QtCore.QDateTime.currentDateTime().toString("hh:mm:ss AP"))



class Dato(Principal):
    def __init__(self):
        Principal.__init__(self)
        self.b_login.clicked.connect(self.validate_User)

    def validate_User(self):
        user = self.l_usuario.text()

        if user == '':
            self.l_status.setText('No se ingreso un usuario')
        else:
            ref = db.reference("/usuarios/")
            res = ref.get()

            for key in res.items():
                if key[0] == user:
                    self.validate_password(user)
    def validate_password(self,user):
        password  = self.l_password.text()

        refp = db.reference("/usuarios/"+user)
        res = refp.get()

        for key in res.items():
            if key[0] == 'password':
                if key[1] == password:
                    self.other()
                    self.l_status.setText("login")
                    pass
                else:
                    self.l_password.setText('')
                    self.l_status.setText("Invalidate Password")
            elif key[0] == 'permisos':
                self.registro.acces = int(key[1])
                self.add.acces = int(key[1])



    def other(self):

        self.close()
        user_name_1(self.l_usuario.text())
        self._Inicio.user_online_on(self.l_usuario.text())
        self._Inicio.user.setText(self.l_usuario.text())
        self._Inicio.show()

    def mousePressEvent(self,event):
        if event.button() == QtCore.Qt.LeftButton:
            self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()
    def mouseMoveEvent(self,event):
        if event.buttons() == QtCore.Qt.LeftButton:
            self.move(event.globalPos()-self.dragPosition)
            event.accept()

app = QApplication([])
p = Dato()
p.show()
app.exec_()

Login.ui

<?xml version="1.0" encoding="UTF-8"?>
  <ui version="4.0">
   <class>MainWindow</class>
   <widget class="QMainWindow" name="MainWindow">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
      <width>351</width>
      <height>551</height>
     </rect>
    </property>
    <property name="windowTitle">
     <string>MainWindow</string>
    </property>
    <property name="windowIcon">
     <iconset>
      <normaloff>icono.ico</normaloff>icono.ico</iconset>
    </property>
    <property name="styleSheet">
     <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 0), stop:1 rgba(255, 255, 255, 0));</string>
    </property>
    <widget class="QWidget" name="centralwidget">
     <property name="styleSheet">
      <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 0), stop:1 rgba(255, 255, 255, 0));</string>
     </property>
     <widget class="QFrame" name="frame">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>90</y>
        <width>351</width>
        <height>461</height>
       </rect>
      </property>
      <property name="styleSheet">
       <string notr="true">background:qlineargradient(spread:pad, x1:0.494249, y1:0, x2:0.472, y2:1, stop:0 rgba(0, 0, 0, 202), stop:1 rgba(51, 51, 51, 218));</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <widget class="QLabel" name="login">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>180</y>
         <width>161</width>
         <height>31</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>14</pointsize>
        </font>
       </property>
       <property name="styleSheet">
        <string notr="true">QLabel#login{
  background:None;
  color:white;
  }</string>
       </property>
       <property name="text">
        <string>Login</string>
       </property>
      </widget>
      <widget class="QLabel" name="icono_usuario">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>230</y>
         <width>32</width>
         <height>32</height>
        </rect>
       </property>
       <property name="styleSheet">
        <string notr="true">QLabel#icono_usuario{
  background:#7A7B7F;
  border:0px;
  background-image:url(Images/usuario.png)
  }</string>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="pixmap">
        <pixmap>new/Imagenes/usuario.png</pixmap>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
      <widget class="QLabel" name="icono_contrasena">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>280</y>
         <width>32</width>
         <height>32</height>
        </rect>
       </property>
       <property name="styleSheet">
        <string notr="true">QLabel#icono_contrasena{
  background:#7A7B7F;
  border :0px;
  background-image:url(Images/pss.png);
  background-repeat:none;
  background-position:center;
  }</string>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="pixmap">
        <pixmap>new/Imagenes/pss.png</pixmap>
       </property>
       <property name="scaledContents">
        <bool>false</bool>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
      <widget class="QLineEdit" name="l_password">
       <property name="geometry">
        <rect>
         <x>42</x>
         <y>280</y>
         <width>291</width>
         <height>32</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>10</pointsize>
        </font>
       </property>
       <property name="styleSheet">
        <string notr="true">QLineEdit#l_password{
  border:0px;
  background:qlineargradient(spread:pad, x1:0.494249, y1:0, x2:0.472, y2:1, stop:0 rgba(0, 0, 0, 183), stop:1 rgba(157, 157, 157, 94));
  color:white;
  }</string>
       </property>
       <property name="inputMethodHints">
        <set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhSensitiveData</set>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="echoMode">
        <enum>QLineEdit::Password</enum>
       </property>
      </widget>
      <widget class="QLineEdit" name="l_usuario">
       <property name="geometry">
        <rect>
         <x>42</x>
         <y>230</y>
         <width>291</width>
         <height>32</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>10</pointsize>
        </font>
       </property>
       <property name="styleSheet">
        <string notr="true">QLineEdit#l_usuario{
  border:0px;
  background:qlineargradient(spread:pad, x1:0.494249, y1:0, x2:0.472, y2:1, stop:0 rgba(0, 0, 0, 183), stop:1 rgba(157, 157, 157, 94));
  color:white;
  }</string>
       </property>
       <property name="inputMask">
        <string/>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="cursorPosition">
        <number>0</number>
       </property>
       <property name="placeholderText">
        <string/>
       </property>
      </widget>
      <widget class="QPushButton" name="b_login">
       <property name="geometry">
        <rect>
         <x>240</x>
         <y>380</y>
         <width>91</width>
         <height>31</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>9</pointsize>
         <weight>50</weight>
         <bold>false</bold>
        </font>
       </property>
       <property name="styleSheet">
        <string notr="true">QPushButton#b_login{
  border:0px;
  background:qlineargradient(spread:pad, x1:0.494249, y1:0, x2:0.472, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(234, 234, 234, 255));
  }


  }
  QPushButton#b_login:hover{
  border:0px;
  background:qlineargradient(spread:pad, x1:0.494249, y1:0, x2:0.472, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(200, 200, 200, 255));

  }
  QPushButton#b_login:pressed{
  border:0px;
  background:qlineargradient(spread:pad, x1:0.494249, y1:0, x2:0.472, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(234, 234, 234, 255));
  border-bottom:2px solid grey;</string>
       </property>
       <property name="text">
        <string>Login</string>
       </property>
      </widget>
      <widget class="QPushButton" name="closed">
       <property name="geometry">
        <rect>
         <x>320</x>
         <y>0</y>
         <width>31</width>
         <height>23</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>9</pointsize>
         <weight>75</weight>
         <bold>true</bold>
        </font>
       </property>
       <property name="styleSheet">
        <string notr="true">QPushButton#closed{
  background:None;
  border:0px;
  color:lightgrey;
  }
  QPushButton#closed:hover{
  color:#D8211D;
  }</string>
       </property>
       <property name="text">
        <string>X</string>
       </property>
      </widget>
      <widget class="QLabel" name="hora">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>440</y>
         <width>101</width>
         <height>20</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>10</pointsize>
        </font>
       </property>
       <property name="styleSheet">
        <string notr="true">QLabel#hora{
  background:None;
  color:white;
  }</string>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
      <widget class="QLabel" name="l_status">
       <property name="geometry">
        <rect>
         <x>60</x>
         <y>330</y>
         <width>231</width>
         <height>21</height>
        </rect>
       </property>
       <property name="styleSheet">
        <string notr="true">QLabel#l_status{
  background:None;
  color:white;
  }</string>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
      <widget class="QComboBox" name="combo_login">
       <property name="enabled">
        <bool>true</bool>
       </property>
       <property name="geometry">
        <rect>
         <x>150</x>
         <y>360</y>
         <width>50</width>
         <height>17</height>
        </rect>
       </property>
       <property name="styleSheet">
        <string notr="true">QComboBox#combo_login{
  background:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 0), stop:1 rgba(255, 255, 255, 0));
  border:0px;
  color:white;
  border-bottom: 1px solid lightblue;
  }


  QComboBox QAbstractItemView
  {
      border: 2px solid darkgray;
      background:grey;
      color: black;
      selection-background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #111, stop: 1 #333);
  }
  QComboBox#combo_login::drop-down
  {
       subcontrol-origin: padding;
       subcontrol-position: top right;
       width: 15px;
       color: white;
       border-left-width: 0px;
       border-left-color: darkgray;
       border-left-style: solid; /* just a single line */
       border-top-right-radius: 3px; /* same radius as the QComboBox */
       border-bottom-right-radius: 3px;
       padding-left: 10px;
   }</string>
       </property>
       <item>
        <property name="text">
         <string>exe1</string>
        </property>
       </item>
       <item>
        <property name="text">
         <string>exe2</string>
        </property>
       </item>
       <item>
        <property name="text">
         <string>exe3</string>
        </property>
       </item>
      </widget>
     </widget>
     <widget class="QLabel" name="label">
      <property name="geometry">
       <rect>
        <x>90</x>
        <y>10</y>
        <width>181</width>
        <height>171</height>
       </rect>
      </property>
      <property name="styleSheet">
       <string notr="true">background:url(Images/Login.png);
  background-repeat:none;
  background-position:center;</string>
      </property>
      <property name="text">
       <string/>
      </property>
     </widget>
    </widget>
   </widget>
   <resources/>
   <connections/>
  </ui>
    
asked by Revsky01 24.08.2018 в 04:20
source

1 answer

1

The cause of this behavior is that the "Press" event is not propagated to the father from the child, but the "Move" event is when, holding the left button, we remove the cursor from the limits of the button ( pass both with the QPushButton and with the button of QComboBox ).

I will clarify that in Linux (tested in ArchLinux with KDE Plasma) there is no way to reproduce the problem with QComboBox at least in my case, now well, in Windows 10 the behavior is completely different because the list of options are not superimposed on the button and the "Move" event is propagated to the parent when we exceed the limits of the QComboBox button (the problem does not occur within the drop-down list). This causes the unwanted behavior shown, by allowing the drag of the window when the click originated in QComboBox , but also, it is displayed in erratic positions when you release the left mouse button.

The error:

  

AttributeError: 'Data' object has no attribute 'dragPosition'

is caused because the "Move" event occurs without the "Press" event previously occurring in the parent, as you define the attribute dragPosition in mousePressEvent when mouseMoveEvent is called and try to use self.dragPosition This does not exist yet. That is why the error does not occur if, before displaying the QComboBox we click on the window, in this case the attribute is already defined, but not updated by mousePressEvent , which causes dragPosition not to have the position of This last click, but the previous one, causing the "jump" appreciated in the GIF.

As a recommendation, never create instance attributes outside __init__ , even if they are only used by certain methods, always initializing them in __init__ (a None if you do not want to give them a value), do not believe them in the other methods.

The problem can be solved in several ways, for example by making sure before processing mouseMoveEvent that a "Press" event previously arrived at the window (since it is blocked by the button):

class Dato(Principal):

    def __init__(self):
        super().__init__()
        self._on_drag = None   # <<<<<<<<<<<<< No te olvides de esto

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self._drag_pos= event.globalPos() - self.frameGeometry().topLeft()
            event.accept()

    def mouseMoveEvent(self, event):
        if event.buttons() == QtCore.Qt.LeftButton and self._drag_pos is not None:
            self.move(event.globalPos() - self._drag_pos)
            event.accept()

    def mouseReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self._drag_pos = None      
            event.accept()

Another option is to simply block the propagation of mouse events to the parent by using the QtCore.Qt.WA_NoMousePropagation attribute:

class Dato(Principal):
    def __init__(self):
        super().__init__()
        self.combo_login.setAttribute(QtCore.Qt.WA_NoMousePropagation)
        # Resto del código
    
answered by 25.08.2018 / 02:43
source