Python Forum
right mouse button click with PyQt5
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
right mouse button click with PyQt5
#1
I'm trying to write a mineweeper program in PyQt5
This is what I already have.
I still have 2 problems:
1* How do I detect a right mouse button click on a button? As you can see I already have a left mouse button click
2* I created a grid of buttons but I'm unable to remove the space between the buttons. How do I do that

I also don't understand the differece between
class Window(QDialog)
and
class Window(QtWidgets.QMainWindow):
import sys
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from functools import partial
from random import randint

class Window(QDialog):
	def __init__(self):
		super().__init__()
		self.setGeometry(50,50,600,300)
		self.setWindowTitle("Minesweeper")
		self.setWindowIcon(QtGui.QIcon('favicon.png'))
		
		self.initGame()		
		
		self.mainPage()
	
	def mainPage(self):
		
		self.createGridLayout()

		windowLayout = QVBoxLayout()
		windowLayout.addWidget(self.horizontalGroupBox)
		self.setLayout(windowLayout)
		
		self.show()
	
	def initGame(self):
		self.initialArray=[[0 for i in range(10)]for j in range(10)]
		self.counterTurns=0
		
		for column in range (0,10):
			for row in range (0,10):
				bomb=randint(0,6)
				if bomb==6:
					self.initialArray[row][column]=9
					if row-1>=0 and self.initialArray[row-1][column]!=9:
						self.initialArray[row-1][column]+=1
					if row+1<=9 and self.initialArray[row+1][column]!=9:
						self.initialArray[row+1][column]+=1
					if column-1>=0 and self.initialArray[row][column-1]!=9:
						self.initialArray[row][column-1]+=1
					if column+1<=9 and self.initialArray[row][column+1]!=9:
						self.initialArray[row][column+1]+=1
					if row-1>=0 and column-1>=0 and self.initialArray[row-1][column-1]!=9:
						self.initialArray[row-1][column-1]+=1
					if row+1<=9 and column-1>=0 and self.initialArray[row+1][column-1]!=9:
						self.initialArray[row+1][column-1]+=1
					if row-1>=0 and column+1<=9 and self.initialArray[row-1][column+1]!=9:
						self.initialArray[row-1][column+1]+=1
					if row+1<=9 and column+1<=9 and self.initialArray[row+1][column+1]!=9:
						self.initialArray[row+1][column+1]+=1
	
		

	def createGridLayout(self):
		self.horizontalGroupBox=QGroupBox()
		layout=QGridLayout()
		
		self.button={}
		
		for column in range (0,10):
			for row in range (0,10):
				self.button[row,column]=QPushButton(self)
				self.button[row,column].setFixedHeight(20)
				self.button[row,column].setFixedWidth(20)
				self.button[row,column].setIcon(QtGui.QIcon('tile_plain.gif'))
				self.button[row,column].clicked.connect(partial(self.buttonPressed,row,column))
				layout.addWidget(self.button[row,column],row,column)
				

		for row in self.initialArray:
			print (row)
		self.horizontalGroupBox.setLayout(layout)
		
	def buttonPressed(self,row,column):
		self.displayEmptyButtons(row,column)
		self.counterTurns+=1
		print ('rij'+str(row)+'\nkolom'+str(column))
		if self.initialArray[row][column]==9:
			print ('bomb!!!! ' + str(self.counterTurns))
		game_busy=0
		values=[1,2,3,4,5,6,7,8]
		for x in self.initialArray:
			print (x)
			if any(i in values for i in x):
				game_busy=1
		if game_busy==0:
			print ('you won')
			
		
				
	def displayEmptyButtons(self,row,column):
		if self.initialArray[row][column]!=0:
			if self.initialArray[row][column]!=10:
				self.button[row,column].setText(str(self.initialArray[row][column]))
			self.initialArray[row][column]=10
		else:
			if self.initialArray[row][column]!=10:
				self.button[row,column].setText(str(self.initialArray[row][column]))
			self.initialArray[row][column]=10
			if row-1>=0:
				self.displayEmptyButtons(row-1,column)
			if row+1<=9:
				self.displayEmptyButtons(row+1,column)
			if column-1>=0:
				self.displayEmptyButtons(row,column-1)
			if column+1<=9:
				self.displayEmptyButtons(row,column+1)
			if row-1>=0 and column-1>=0:
				self.displayEmptyButtons(row-1,column-1)
			if row+1<=9 and column-1>=0:
				self.displayEmptyButtons(row+1,column-1)
			if row-1>=0 and column+1<=9:
				self.displayEmptyButtons(row-1,column+1)
			if row+1<=9 and column+1<=9:
				self.displayEmptyButtons(row+1,column+1)

			
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Window()
    sys.exit(app.exec_())
Reply
#2
To remove the space between buttons, you must apply these settings on the layout (or edit the Layout section in QtDesigner):
        self.gridLayout.setSpacing(0)
        self.gridLayout.setContentsMargins(0,0,0,0)
Then to detect the type of mouse click, or even the mouse wheel, you must install an event filter on each button:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(QtWidgets.QMainWindow):
    def setupUi(self, Form):
        self.gridLayout = QtWidgets.QGridLayout(Form)
        self.gridLayout.setSpacing(0)
        self.gridLayout.setContentsMargins(0,0,0,0)
        self.gridLayout.setObjectName("gridLayout")

        self.pushButton_1 = QtWidgets.QPushButton(Form)
        self.pushButton_1.setFixedSize(QtCore.QSize(20, 20))
        self.pushButton_1.setObjectName("pushButton_1")
        self.gridLayout.addWidget(self.pushButton_1, 0, 0, 1, 1)

        self.pushButton_2 = QtWidgets.QPushButton(Form)
        self.pushButton_2.setFixedSize(QtCore.QSize(20, 20))
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)

        self.pushButton_3 = QtWidgets.QPushButton(Form)
        self.pushButton_3.setFixedSize(QtCore.QSize(20, 20))
        self.pushButton_3.setObjectName("pushButton_3")
        self.gridLayout.addWidget(self.pushButton_3, 0, 1, 1, 1)

        self.pushButton_4 = QtWidgets.QPushButton(Form)
        self.pushButton_4.setFixedSize(QtCore.QSize(20, 20))
        self.pushButton_4.setObjectName("pushButton_4")
        self.gridLayout.addWidget(self.pushButton_4, 1, 1, 1, 1)

        self.pushButton_1.installEventFilter(self)
        self.pushButton_2.installEventFilter(self)
        self.pushButton_3.installEventFilter(self)
        self.pushButton_4.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            if event.button() == QtCore.Qt.LeftButton:
                print(obj.objectName(), "Left click")
            elif event.button() == QtCore.Qt.RightButton:
                print(obj.objectName(), "Right click")
            elif event.button() == QtCore.Qt.MiddleButton:
                print(obj.objectName(), "Middle click")
        return QtCore.QObject.event(obj, event)


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())
Finally, the choice between a Dialog and a MainWindow depend of what you intend to do with it. The dialog usually have some action button (apply, ok, cancel...), and therefore they have accepted and rejected signals. The MainWindow have more complex features, such as a top menu and status bar. It is very well detailled in Qt docs:

https://doc.qt.io/qt-5/qmainwindow.html
https://doc.qt.io/archives/qt-4.8/qdialog.html
Reply
#3
There is still something going wrong with the mouse click. Any idea what I'm doing wrong?
This is the error message I'm getting:

Traceback (most recent call last):
File "minesweeper_A01.py", line 53, in eventFilter
if event.button() == Qt.LeftButton:
AttributeError: 'QEvent' object has no attribute 'button'


------------------
(program exited with code: 3)

Druk op een toets om door te gaan. . .


import sys
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from functools import partial
from random import randint

#class Window(QWidget):
class Window(QMainWindow):
	def __init__(self):
		super(Window,self).__init__()
		self.setWindowTitle("Minesweeper")
		self.setWindowIcon(QtGui.QIcon('ekopak-favicon.png'))
		
		fileAction = QAction("New", self)
		fileAction.triggered.connect(self.init_game)

		mainMenu = self.menuBar()
		fileMenu = mainMenu.addMenu('&File')
		fileMenu.addAction(fileAction)
		
		self.setMouseTracking(True)
		
		self.init_game()		
		
		self.main_page()
	
	def main_page(self):		
		self.button={}
		
		self.centralwidget = QWidget()
		self.setCentralWidget(self.centralwidget)
        
		horizontalLayout=QHBoxLayout(self.centralwidget)
		for column in range (0,10):
			verticalLayout=QVBoxLayout()
			verticalLayout.setSpacing(0)
			for row in range (0,10):
				self.button[row,column]=QPushButton(self)
				self.button[row,column].setFixedHeight(20)
				self.button[row,column].setFixedWidth(20)
				self.button[row,column].setContentsMargins(0,0,0,0)
				self.button[row,column].setIcon(QtGui.QIcon('tile_plain.gif'))
				self.button[row,column].installEventFilter(self)
				self.button[row,column].clicked.connect(partial(self.button_pressed,row,column))
				verticalLayout.addWidget(self.button[row,column])
			horizontalLayout.addLayout(verticalLayout)
			horizontalLayout.setSpacing(0)
		self.show()
	
	def eventFilter(self,obj,event):
		print('button pressed')
		if event.button() == Qt.LeftButton:
			print(obj.objectName(), "Left click")
		elif event.button() == Qt.RightButton:
			print(obj.objectName(), "Right click")
		elif event.button() == Qt.MiddleButton:
			print(obj.objectName(), "Middle click")
		return QObject.event(obj, event)


		

	
	def init_game(self):
		self.initialArray=[[0 for i in range(10)]for j in range(10)]
		self.counterTurns=0
		
		for column in range (0,10):
			for row in range (0,10):
				bomb=randint(0,6)
				if bomb==6:
					self.initialArray[row][column]=9
					if row-1>=0 and self.initialArray[row-1][column]!=9:
						self.initialArray[row-1][column]+=1
					if row+1<=9 and self.initialArray[row+1][column]!=9:
						self.initialArray[row+1][column]+=1
					if column-1>=0 and self.initialArray[row][column-1]!=9:
						self.initialArray[row][column-1]+=1
					if column+1<=9 and self.initialArray[row][column+1]!=9:
						self.initialArray[row][column+1]+=1
					if row-1>=0 and column-1>=0 and self.initialArray[row-1][column-1]!=9:
						self.initialArray[row-1][column-1]+=1
					if row+1<=9 and column-1>=0 and self.initialArray[row+1][column-1]!=9:
						self.initialArray[row+1][column-1]+=1
					if row-1>=0 and column+1<=9 and self.initialArray[row-1][column+1]!=9:
						self.initialArray[row-1][column+1]+=1
					if row+1<=9 and column+1<=9 and self.initialArray[row+1][column+1]!=9:
						self.initialArray[row+1][column+1]+=1	
		for row in self.initialArray:
			print (row)

		
	def button_pressed(self,row,column):
		self.display_empty_buttons(row,column)
		self.counterTurns+=1
		print ('rij'+str(row)+'\nkolom'+str(column))
		if self.initialArray[row][column]==9:
			print ('bomb!!!! ' + str(self.counterTurns))
		game_busy=0
		values=[1,2,3,4,5,6,7,8]
		for x in self.initialArray:
			print (x)
			if any(i in values for i in x):
				game_busy=1
		if game_busy==0:
			print ('you won')
			
		
				
	def display_empty_buttons(self,row,column):
		#the value of initialArray can be 0-8, 9 is for a bomb, 10 is if it has been opened
		if self.initialArray[row][column]!=0:
			if self.initialArray[row][column]!=10:
				if self.initialArray[row][column]==0:
					self.button[row,column].setIcon(QtGui.QIcon('tile_clicked.gif'))
				elif self.initialArray[row][column]==1:
					self.button[row,column].setIcon(QtGui.QIcon('tile_1.gif'))	
				elif self.initialArray[row][column]==2:
					self.button[row,column].setIcon(QtGui.QIcon('tile_2.gif'))
				elif self.initialArray[row][column]==3:
					self.button[row,column].setIcon(QtGui.QIcon('tile_3.gif'))	
				elif self.initialArray[row][column]==4:
					self.button[row,column].setIcon(QtGui.QIcon('tile_4.gif'))	
				elif self.initialArray[row][column]==5:
					self.button[row,column].setIcon(QtGui.QIcon('tile_5.gif'))
				elif self.initialArray[row][column]==6:
					self.button[row,column].setIcon(QtGui.QIcon('tile_6.gif'))	
				elif self.initialArray[row][column]==7:
					self.button[row,column].setIcon(QtGui.QIcon('tile_7.gif')) 
				elif self.initialArray[row][column]==8:
					self.button[row,column].setIcon(QtGui.QIcon('tile_8.gif'))
				elif self.initialArray[row][column]==9:
					self.button[row,column].setIcon(QtGui.QIcon('tile_mine.gif'))
				else:
					self.button[row,column].setText(str(self.initialArray[row][column]))
			self.initialArray[row][column]=10
		else:
			if self.initialArray[row][column]!=10:
				if self.initialArray[row][column]==0:
					self.button[row,column].setIcon(QtGui.QIcon('tile_clicked.gif'))
				else:
					self.button[row,column].setText(str(self.initialArray[row][column]))
			self.initialArray[row][column]=10
			if row-1>=0:
				self.displayEmptyButtons(row-1,column)
			if row+1<=9:
				self.displayEmptyButtons(row+1,column)
			if column-1>=0:
				self.displayEmptyButtons(row,column-1)
			if column+1<=9:
				self.displayEmptyButtons(row,column+1)
			if row-1>=0 and column-1>=0:
				self.displayEmptyButtons(row-1,column-1)
			if row+1<=9 and column-1>=0:
				self.displayEmptyButtons(row+1,column-1)
			if row-1>=0 and column+1<=9:
				self.displayEmptyButtons(row-1,column+1)
			if row+1<=9 and column+1<=9:
				self.displayEmptyButtons(row+1,column+1)

#messagebox bomb pressed
#messagebox won
#rightclick add flag
					
			
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    ex = Window()
    sys.exit(app.exec_())
Reply
#4
It is because not all event have the same properties. Therefore you must verify what type of event it is before looking for the button attribute.

if event.type() == QtCore.QEvent.MouseButtonPress:
Reply
#5
Thanks for the help, it's working now
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  tkinter - touchscreen, push the button like click the mouse John64 5 744 Jan-06-2024, 03:45 PM
Last Post: deanhystad
  Figure Gets Larger Every time I click a show button joshuagreineder 2 1,270 Aug-11-2022, 06:25 AM
Last Post: chinky
  [Tkinter] Modify Class on Button Click KDog 4 3,903 May-11-2021, 08:43 PM
Last Post: KDog
  [Tkinter] Mouse click without use bind ATARI_LIVE 8 7,256 Oct-23-2020, 10:41 PM
Last Post: ATARI_LIVE
  [Tkinter] Button click problem using OOP JohnB 5 3,521 Oct-21-2020, 12:43 PM
Last Post: JohnB
  tkinter | Button color text on Click Maryan 2 3,314 Oct-09-2020, 08:56 PM
Last Post: Maryan
  [Tkinter] program unresponsive during pynput mouse click RobotTech 1 3,439 May-07-2020, 04:43 PM
Last Post: RobotTech
  Closing window on button click not working kenwatts275 4 3,664 May-03-2020, 01:59 PM
Last Post: deanhystad
  [PyQt] Pyqt5: How do you make a button that adds new row with data to a Qtablewidget YoshikageKira 6 6,873 Jan-02-2020, 04:32 PM
Last Post: Denni
  [Tkinter] Mouse click event not working on multiple tkinter window evrydaywannabe 2 3,710 Dec-16-2019, 04:47 AM
Last Post: woooee

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020