Time lag during a chess game in pyqt5 python - python

I've been designing a GUI-based chess game in PyQt5 (Python) . Since it is incomplete , there are some issues . But the biggest issue is , that after every move , the time lag in the GUI increases . After a particular time (say , move 8) , the GUI would almost stop working . Please help . The code is given below :
import PyQt5
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import uic
import chess
import sys
import tabulate
class Chess_App(QtWidgets.QMainWindow):
def __init__(self):
super(Chess_App, self).__init__()
uic.loadUi("CHESS.ui", self)
self.move_name = ""
self.move = ""
self.board_rows = [8,7,6,5,4,3,2,1]
self.board_columns = 'a b c d e f g h'.split(" ")
# variable_needed = f"{self.board_columns[7-(n//8)]}{self.board_rows[n%8]}"
font = QtGui.QFont()
font.setPointSize(1)
self.win = None
self.draw = None
self.valid_move = True
self.Chess_Board = {n:QtWidgets.QPushButton(self) for n in range(64)}
for i in range(64):
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : lightgreen ; color : lightgreen}")
self.Chess_Board[i].setFont(font)
self.Chess_Board[i].setObjectName(f"{self.board_columns[i%8]}{self.board_rows[i//8]}")
self.lineEdit_2.setDisabled(True)
for i in range(64):
if (i // 8) % 2 == 0:
if i % 2 == 0:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
if (i // 8) % 2 == 1:
if i % 2 == 1:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
self.Chess_Board[i].setGeometry(60+((i%8)*50),140+((i//8)*50),50,50)
self.Chess_Board[i].clicked.connect(self.initiate_move)
self.lineEdit.isReadOnly()
self.pushButton_A.clicked.connect(self.play_move)
self.pushButton_B.clicked.connect(self.resignation)
self.pushButton_C.clicked.connect(self.draw_game)
self.pushButton_D.clicked.connect(self.save_game)
self.pushButton_E.clicked.connect(self.reset_game)
self.board = chess.Board()
self.chessboard()
self.show_board()
self.show()
def chessboard(self):
self.pgn = self.board.epd()
self.final_list = []
self.printable_list = []
pieces = self.pgn.split(" ", 1)[0]
rows = pieces.split("/")
for row in rows:
self.initial_list = []
for chessmen in row:
if chessmen.isdigit():
for i in range(0, int(chessmen)):
self.initial_list.append(".")
else:
self.initial_list.append(chessmen)
self.final_list.append(self.initial_list)
def initiate_move(self):
for i in range(64):
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : lightgreen ; color : lightgreen}")
if (i // 8) % 2 == 0:
if i % 2 == 0:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
if (i // 8) % 2 == 1:
if i % 2 == 1:
self.Chess_Board[i].setStyleSheet("QPushButton {background-color : white}")
self.value = self.sender()
self.move = self.value.text().upper()
if self.move == "":
pass
elif len(self.move) == 1:
if self.move == "P":
pass
else:
self.move_name += self.move
self.value.setStyleSheet("QPushButton {background-color : cyan}")
for i in range(64):
self.Chess_Board[i].clicked.connect(self.play_move)
def play_move(self):
self.textBrowser.setText("")
self.valid_move = True
self.button = self.sender()
if len(self.button.text()) == 1:
self.move_name += f"x{self.button.objectName()}"
if self.button.text() == "":
self.move_name += self.button.objectName()
# if self.lineEdit.isEnabled():
# self.move = self.lineEdit.text()
# elif self.lineEdit_2.isEnabled():
# self.move = self.lineEdit_2.text()
try:
self.board.push_san(self.move_name)
except Exception as ex:
self.textBrowser.setText(f"{ex}")
self.valid_move = False
if self.valid_move == True:
if self.lineEdit.isEnabled():
self.lineEdit.setDisabled(True)
self.lineEdit_2.setDisabled(False)
else:
self.lineEdit.setDisabled(False)
self.lineEdit_2.setDisabled(True)
elif self.valid_move == False:
self.move_name = ""
if self.board.is_checkmate():
self.textBrowser.setText("Checkmate !")
self.win = True
self.end_the_game()
if self.board.is_variant_draw():
self.textBrowser.setText("Draw !")
self.draw = True
self.end_the_game()
if self.board.is_stalemate():
self.textBrowser.setText("Stalemate !")
self.draw = True
self.end_the_game()
if self.board.is_fifty_moves():
self.textBrowser.setText("Draw by fifty-move rule !")
self.draw = True
self.end_the_game()
if self.board.is_repetition():
self.textBrowser.setText("Draw by three-fold repitition !")
self.draw = True
self.end_the_game()
self.chessboard()
self.show_board()
for i in range(64):
self.Chess_Board[i].clicked.connect(self.initiate_move)
self.move = ""
self.move_name = ""
def show_board(self):
for x in range(8):
for y in range(8):
if self.final_list[x][y].isupper():
self.Chess_Board[x*8+y].setText(f"{self.final_list[x][y]}".upper())
self.Chess_Board[x*8+y].setIcon(QtGui.QIcon(f"{self.final_list[x][y]}#.png"))
self.Chess_Board[x*8+y].setIconSize(QtCore.QSize(40,40))
elif self.final_list[x][y].islower():
self.Chess_Board[x*8+y].setText(f"{self.final_list[x][y]}".lower())
self.Chess_Board[x*8+y].setIcon(QtGui.QIcon(f"{self.final_list[x][y]}&.png"))
self.Chess_Board[x*8+y].setIconSize(QtCore.QSize(40,40))
elif self.final_list[x][y] == ".":
self.Chess_Board[x*8+y].setIcon(QtGui.QIcon())
self.Chess_Board[x*8+y].setText("")
def reset_game(self):
self.board.reset()
self.lineEdit.setText("")
self.lineEdit_2.setText("")
self.lineEdit.setDisabled(False)
self.lineEdit_2.setDisabled(True)
self.textBrowser.setText("")
self.chessboard()
self.show_board()
self.end_the_game()
def draw_game(self):
self.draw = True
self.end_the_game()
self.textBrowser.setText("It's a draw .")
def resignation(self):
if self.lineEdit.text() == self.lineEdit_2.text() == "":
self.textBrowser.setText("Match Aborted")
else:
if self.move == self.lineEdit.text():
self.win = True
self.end_the_game()
who_resigned = "Black"
elif self.move == self.lineEdit_2.text():
self.win = False
self.end_the_game()
who_resigned = "White"
self.textBrowser.setText(f"{who_resigned} resigned")
def save_game(self):
self.chesstable = tabulate.tabulate(self.final_list, tablefmt="grid", stralign="left")
with open("chess_save_list.txt","a") as writer:
writer.write(self.chesstable)
def end_the_game(self):
if self.win != self.draw:
self.pushButton_A.setDisabled(True)
self.pushButton_B.setDisabled(True)
self.pushButton_C.setDisabled(True)
self.win, self.draw = None, None
elif self.win == self.draw:
self.pushButton_A.setDisabled(False)
self.pushButton_B.setDisabled(False)
self.pushButton_C.setDisabled(False)
app = QtWidgets.QApplication(sys.argv)
window = Chess_App()
app.exec_()
The link to get the .ui link for the code : https://github.com/Vishal01-VKP/Python-Projects/blob/master/GUIs/Games/Chess%20-%20By%20VK/CHESS.ui
Thank you .

It is lagging over time because after each and every move you are connecting the clicked signal again for all 64 buttons in play_move and initiate_move.. connected signal's slot function will be executed in event loop, causing the lag in game
if you are connecting the signal again doesn't mean it will disconnect previous signal but rather add other signals, so after one or two moves each move will cause the 64 signals to connect again, after 5 to 6 moves it will have more than 5000 slots connected to each signal..
If the signal is connected to slot, it will remain connected until it is destroyed or explicitly disconnected..
So Modify your code accordingly so signals doesn't have to be connected again or Disconnect the signals before connecting them again(It could work but not recommended)

Related

Python Ursina hide UI

I have an GUI inventory and I don't know how to hide it and all the items there are inside. I tried to make the class Inventory(Entity) enabled or not and it didn't worked because it only gets enables and never disabled. This is my first post so, please, be nice.
My code:
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
app = Ursina()
class Inventory(Entity):
def __init__(self):
player.enabled = False
super().__init__(
parent = camera.ui,
model = 'quad',
scale = (.5, .8),
origin = (-.5, .5),
position = (-.3,.4),
texture = 'white_cube',
texture_scale = (5,8),
color = color.dark_gray
)
self.item_parent = Entity(parent=self, scale=(1/5,1/8))
enable = False
def input(key):
if key == 'f':
inventory_enable()
def inventory_enable():
inventory = Inventory()
Inventory().enable = False
...
Setting entity.enabled = False will deactivate it and all it's children. To make it reappear, set it back to True.
app = Ursina()
class Inventory(Entity):
def __init__(self):
player.enabled = False
super().__init__(
parent = camera.ui,
)
self.inventory_ui = Entity(parent = self,
model = 'quad',
scale = (.5, .8),
origin = (-.5, .5),
position = (-.3,.4),
texture = 'white_cube',
texture_scale = (5,8),
color = color.dark_gray,
enable = True
)
self.item_parent = Entity(parent=self.inventory_ui, scale=(1/5,1/8))
def find_free_spot(self):
taken_spots = [(int(e.x), int(e.y)) for e in self.item_parent.children]
for y in range(8):
for x in range(5):
if not (x,-y) in taken_spots:
return (x,-y)
def append(self, item):
icon = Draggable(
parent = Inventory().item_parent,
model = 'quad',
texture = item,
color = color.white,
origin = (-.5,.5),
position = self.find_free_spot(),
z = -.1,
)
name = item.replace('_', ' ').title()
icon.tooltip = Tooltip(name)
icon.tooltip.background.color = color.color(0,0,0,.8)
def drag():
icon.org_pos = (icon.x, icon.y)
def drop():
icon.x = int(icon.x)
icon.y = int(icon.y)
'''if the spot is taken, swap positions'''
for c in self.children:
if c == icon:
continue
if c.x == icon.x and c.y == icon.y:
print('swap positions')
c.position = icon.org_pos
icon.drag = drag
icon.drop = drop
#removed load_texture
grass_texture = "assets/grass.png"
soil_texture = "assets/soil.png"
stone_texture = "assets/stone.png"
wood_texture = "assets/wood.png"
sky_texture = load_texture("assets/skybox.png")
current_texture = grass_texture
def update():
global current_texture
if held_keys['1']: current_texture = grass_texture
if held_keys['2']: current_texture = soil_texture
if held_keys['3']: current_texture = stone_texture
if held_keys['4']: current_texture = wood_texture
# added
if held_keys['g']:
save_game()
if held_keys['left mouse'] or held_keys['right mouse']:
hand.active()
else:
hand.passive()
def input(key):
key_f = 0
if key == 'escape':
quit()
if key == 'f' and key_f == 0:
key_f = 1
inventory_enable()
else:
key_f = 0
inventory_close()
def inventory_close():
Inventory().inventory_ui.enable = False
def inventory_enable():
inventory = Inventory()
Inventory().enable = False
def add_item():
Inventory().append(random.choice(('bag', 'bow_arrow', 'gem', 'orb', 'sword')))
for i in range(7):
add_item()
add_item_button = Button(
scale = (.1,.1),
x = -.5,
color = color.lime.tint(-.25),
text = '+',
tooltip = Tooltip('Add random item'),
on_click = add_item
)
By setting gui.enable = False or gui.visible = False you can hide the gui. gui.enable = False disables it and all of his parents, gui.visible = False just makes it invisible.

Attribute Error: List object has no attribute CheckClick

In the Swap function, I am checking under some index a button class instance, which I checked using print statements, but for some reason it still gives me an error saying that it has no such attribute check click. Any tips on formatting are also welcome, I am just a beginner. I am using three different arrays to hold various instances, values and coordinates for each corresponding array position. I am trying to make a sort of match 3 game. Thanks for any help
from os import access
import pygame,sys
from random import randrange
import numpy
#Constants
Columns =5
Rows = 5
X,Y = 320,0
class Button:
def __init__(self,x,y,image,scale):
self.x = x
self.y=y
self.image = pygame.transform.scale(image,(scale,scale))
self.scale = scale
self.rect = self.image.get_rect(topleft=(x,y))
self.clicked = False
self.Action = False
def Draw(self):
Win.blit(self.image,(self.x,self.y))
def CheckClick(self):
isClicked = False
mousepos= pygame.mouse.get_pos()
if self.rect.collidepoint(mousepos):
if pygame.mouse.get_pressed()[0] ==1 and self.clicked == False:
self.clicked = True
self.Action = True
if pygame.mouse.get_pressed()[0] ==0:
self.clicked = False
return self.Action
#Win
WinWidth, WinHeight = 1280,800
Win = pygame.display.set_mode((WinWidth,WinHeight))
#IMAGES
test_img = pygame.image.load("test.png")
red_img = pygame.image.load("Red.png")
green_img = pygame.image.load("green.png")
blue_img = pygame.image.load("blue.png")
#Board
Board = [[ randrange(0,3) for column in range(Columns)] for row in range(Rows) ]
BoardObjs = []
BoardXYs = [[None for column in range(Columns)]for row in range(Rows)]
#Fill BoardXYS
for k in range(len(Board)):
for j in range(len(Board[1])):
BoardXYs[k][j] = [X,Y]
X += 160
X = 320
Y += 160
for r in range(len(Board)):
for t in range(len(Board[1])):
if Board[r][t] == 0:
BoardObjs.append(Button(BoardXYs[r][t][0],BoardXYs[r][t][1],red_img,100))
if Board[r][t] == 1:
BoardObjs.append(Button(BoardXYs[r][t][0],BoardXYs[r][t][1],green_img,100))
if Board[r][t] == 2:
BoardObjs.append(Button(BoardXYs[r][t][0],BoardXYs[r][t][1],blue_img,100))
BoardObjs = [[BoardObjs[0],BoardObjs[1],BoardObjs[2],BoardObjs[3],BoardObjs[4]],
[BoardObjs[5],BoardObjs[6],BoardObjs[7],BoardObjs[8],BoardObjs[9]],
[BoardObjs[10],BoardObjs[11],BoardObjs[12],BoardObjs[13],BoardObjs[14]],
[BoardObjs[15],BoardObjs[16],BoardObjs[17],BoardObjs[18],BoardObjs[19]],
[BoardObjs[20],BoardObjs[21],BoardObjs[22],BoardObjs[23],BoardObjs[24]]]
print(len(Board))
print(len(BoardObjs))
#Images
img_0 = pygame.Rect(0,0,64,64)
TouchingReds = 0
def CheckMatches(Board):
VerticalMatch = False
HorizontalMatch = False
for m in range(len(Board)):
for n in range(len(Board[1])-2):
if Board[m][n]==Board[m][n+1]==Board[m][n+2]:
HorizontalMatch = True
Board[m][n] = None
Board[m][n+1] = None
Board[m][n+2] = None
BoardObjs[m][n] = None
BoardObjs[m][n+1] = None
BoardObjs[m][n+2] = None
for o in range(len(Board[1])-2):
for u in range(len(Board)):
if Board[o][u]==Board[o+1][u]==Board[o+2][u]:
VerticalMatch = True
Board[o][u] = None
Board[o+1][u] = None
Board[o+2][u] = None
BoardObjs[o][u] = None
BoardObjs[o+1][u] = None
BoardObjs[o+2][u] = None
def Draw(Board,BoardXYs):
DoAppend = True
Win.fill((255,255,255))
for y in range(len(BoardObjs)):
for u in range(len(BoardObjs[1])):
if BoardObjs[y][u] != None:
BoardObjs[y][u].Draw()
pygame.display.update()
def Swap():
FirstClick = False
for i in range(len(BoardObjs)):
for t in range(len(BoardObjs[1])):
if BoardObjs[i][t] != None:
if BoardObjs[i][t].CheckClick and FirstClick == True:
BoardObjs[num][num2]=BoardObjs[i][t]
BoardObjs[i][t]=Buffer
FirstClick = False
print(BoardObjs[i][t])
if BoardObjs[i][t] !=None:
if BoardObjs[i][t].CheckClick:
Buffer = BoardObjs[i]
num =i
num2 = t
FirstClick = True
#ZEROS - RED
#ONES - GREEN
#TWOS - BLUE
clock = pygame.time.Clock()
def GameLoop():
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
CheckMatches(Board)
Draw(Board,BoardXYs)
Swap()
pygame.quit()
sys.exit()
if __name__ == "__main__":
GameLoop()
The mistake is in the Swap() function. Buffer is assigned to an item in the grid (BoardObjs[i][t]=Buffer). So Buffer needs to be a Button object instead of a row (list of objects):
Buffer = BoardObjs[i]
Buffer = BoardObjs[i][t]
The initialization of the board can be simplified:
#Board
Board = [[randrange(0,3) for column in range(Columns)] for row in range(Rows) ]
BoardXYs = [[(j*160+320, k*160) for j in range(Columns)]for k in range(Rows)]
BoardObjs = []
for r in range(len(Board)):
BoardObjs.append([])
for t in range(len(Board[1])):
image = [red_img, green_img, blue_img][board[r][t]]
BoardObjs[-1].append(Button(*BoardXYs[r][t], image, 100))
The CheckClick function you added is a function, not an attribute. Make sure to put parentheses after the name, even if it takes no argument.
Try, BoardObjs[i][t].CheckClick()

I'm trying to create a Kivy based Tic-Tac-Toe game in Python using the Minimax algorithm, but the computer will not counter my movements

As the title suggests, I'm trying to create a Tic-Tac-Toe game using the Minimax algorithm.
My problem occurs when the computer is supposed to counter my movements. Instead of doing so, it plays in what seems to be random yet repetitive patterns.
This is my first time using the Minimax algorithm, so any help or advice would be welcomed.
Thanks in advance!
Here is my code:
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
import numpy as np
import random
class Board(GridLayout):
def __init__(self):
GridLayout.__init__(self)
self.cols = 3
self.level = 8
self.listBoard = []
array = ([0, 0, 0],
[0, 0, 0],
[0, 0, 0])
self.array = np.array(array)
for i in range(self.cols):
listLine = []
for j in range(self.cols):
cell = Button(font_size=50, on_press=self.click)
cell.i = i
cell.j = j
self.add_widget(cell)
listLine.append(cell)
self.listBoard.append(listLine)
self.check = False
start = random.randint(0, 1)
self.player = ''
self.computer = ''
# player is 1, computer is 10
if start == 1:
self.player = 'X'
self.computer = 'O'
else:
self.computer = 'X'
self.player = 'O'
move = self.minimax(self.array.copy(), self.level)
self.listBoard[move[0]][move[1]].text = self.computer
self.array[move[0]][move[1]] = 10
print(self.array)
def click(self, button):
if button.text == '' and not self.check:
button.text = self.player
self.array[button.i][button.j] = 1
print(self.array)
if self.check_victory(self.array) == 'Player':
print('Player Wins!')
self.check = True
moves = self.find_moves(self.array)
if moves.any() and not self.check:
move = self.minimax(self.array.copy(), self.level)
self.listBoard[move[0]][move[1]].text = self.computer
self.array[move[0]][move[1]] = 10
print(self.array)
elif self.check_victory(self.array) == 'None':
print('Tie!')
self.check = True
if self.check_victory(self.array) == 'Computer' and not self.check:
print('Computer Wins!')
self.check = True
moves = self.find_moves(self.array)
if not moves.any() and self.check_victory(self.array) == 'None' and not self.check:
print('Tie!')
def find_moves(self, array):
moves = np.argwhere(array == 0)
return moves
def check_victory(self, array):
temp1 = array
temp2 = np.rot90(array)
column1 = np.sum(temp1, axis=0)
column2 = np.sum(temp2, axis=0)
diagonal1 = np.diag(temp1).sum()
diagonal2 = np.diag(temp2).sum()
for i in range(3):
if column1[i] % 10 == 3 or column2[i] % 10 == 3:
return 'Player'
if column1[i] / 10 == 3 or column2[i] / 10 == 3:
return 'Computer'
if diagonal1 % 10 == 3 or diagonal2 % 10 == 3:
return 'Player'
if diagonal1 / 10 == 3 or diagonal2 / 10 == 3:
return 'Computer'
return 'None'
def minimax(self, game_state, level):
moves = self.find_moves(game_state)
best_move = moves[0]
best_score = float('-inf')
for move in moves:
clone = self.next_state(game_state.copy(), move[0], move[1], 'Computer')
score = self.min_play(clone, level - 1)
if score > best_score:
best_move = move
best_score = score
return best_move
def min_play(self, game_state, level):
if self.check_victory(game_state) == 'Player' or level == 0:
return self.evaluate(game_state)
moves = self.find_moves(game_state)
best_score = float('inf')
for move in moves:
clone = self.next_state(game_state.copy(), move[0], move[1], 'Player')
score = self.max_play(clone, level - 1)
if score < best_score:
# best_move = move
best_score = score
return best_score
def max_play(self, game_state, level):
if self.check_victory(game_state) == 'Computer' or level == 0:
return self.evaluate(game_state)
moves = self.find_moves(game_state)
best_score = float('-inf')
for move in moves:
clone = self.next_state(game_state, move[0], move[1], 'Computer')
score = self.min_play(clone, level - 1)
if score > best_score:
# best_move = move
best_score = score
return best_score
def next_state(self, array, i, j, who):
if who == 'Player':
array[i][j] = 1
else:
array[i][j] = 10
return array
def evaluate(self, array):
if self.check_victory(array) == 'Player':
return -1
if self.check_victory(array) == 'Computer':
return 1
return 0
class TestApp(App):
def build(self):
self.title = 'based graphics'
return Board()
TestApp().run()

How to Erase/remove particular portion of QGraphicPathItem?

I am adding QgraphicsPathItem to scene and want to erase particular portion of the Qgraphicspathitem. I am using QgraphicsrectItem as Eraser here.Both the items are colliding, but the QgraphicsPathItem is not getting erased.It remains the same in the scene.I am subtracting the two paths and adding it to the QGraphicspathItem
class GraphicsSceneClass(QGraphicsScene):
def __init__(self):
super().__init__()
self.setItemIndexMethod(QGraphicsScene.NoIndex)
self.setBackgroundBrush(QBrush(Qt.black))
self.setSceneRect(0,0,1000,1000)
self.horizontal=QHBoxLayout()
self.widget=QWidget()
self.drawrect=False
self.gridOn = 0
self.selectionMode = 1
self.targetForLine = QRect()
self.drawEnd = True
self.resizemode=0
self.eraser_item = None
self.erasing=False
self.rect=QGraphicsRectItem()
def mousePressEvent(self,event):
try:
sampleTransform = QTransform()
self.objectAtMouse = self.itemAt(event.scenePos(), sampleTransform)
if self.selectionMode == 2:
if self.drawEnd == True:
self.drawEnd = False
elif self.drawEnd == False:
self.drawEnd = True
self.drawLineObj = None
if self.drawEnd == False:
self.lineInsertPoint = self.TargPosForLine(event.scenePos(), "ForLine")
tempPainterPath = QPainterPath()
self.drawLineObj = QGraphicsPathItem()
self.drawLineObj.setPos(self.lineInsertPoint.x(), self.lineInsertPoint.y())
self.drawLineObj.setPen(QPen(Qt.NoPen))
self.drawLineObj.setBrush(QBrush(QColor(Qt.gray)))
self.drawLineObj.setPath(tempPainterPath)
self.addItem(self.drawLineObj)
self.drawLineObj.setFlag(QGraphicsItem.ItemIsSelectable)
if event.buttons() == Qt.RightButton and self.resizemode == 1:
self.erasing = True
self.rect.setRect(event.scenePos().x()-5, event.scenePos().y()-5, 10, 10)
print(event.pos().x(),event.pos().y())
self.addItem(self.rect)
self.rect.setPen(QColor(Qt.red))
except Exception as e:
print("Error in mousepress",e)
def mouseMoveEvent(self,event):
try:
if self.selectionMode == 2 and self.drawEnd == False and self.erasing == False:
f1 = QPainterPath()
gridPos = self.TargPosForLine(event.scenePos(), "ForLine")
f1.moveTo(0, 0)
f1.lineTo(0, 6)
f1.lineTo((gridPos.x() - self.lineInsertPoint.x()), 6)
f1.lineTo((gridPos.x() - self.lineInsertPoint.x()), 0)
f1.closeSubpath()
self.drawLineObj.setPath(f1)
self.drawLineObj.setPos(self.lineInsertPoint.x(), self.lineInsertPoint.y() + 5)
self.drawLineObj.setBrush(QBrush(QColor(Qt.gray)))
pen = QPen(QColor(Qt.gray))
pen.setWidth(0)
self.drawLineObj.setPen(pen)
self.drawLineObj._property = []
self.drawLineObj._angle = 0
if self.selectionMode == 2 and self.drawEnd == True:
self.targetForLine = self.TargPosForLine(event.scenePos(), "ForRect")
self.update()
if event.buttons() & Qt.RightButton and self.erasing:
print(event.scenePos().x(),event.scenePos().y())
self.rect.setRect(event.scenePos().x() - 5, event.scenePos().y() - 5,
10, 10)
for item in self.collidingItems(self.rect):
new = item.path()-(self.rect.shape())
item.setPath(new)
print('collided')
else:
self.targetForLine = QRect()
except Exception as e:
print("Error in mousemove",e)
def mouseReleaseEvent(self, event):
if self.drawrect==True or self.tLext==2 or self.tRext==2 or self.BLext==2 or self.BRext==2:
self.drawrect=False
self.tLext=0
self.tRext=0
self.BLext=0
self.BRext=0
QApplication.changeOverrideCursor(Qt.ArrowCursor)
QApplication.setOverrideCursor(Qt.ArrowCursor)
mainWindow.pointer.setChecked(False)
if self.rect != None:
self.removeItem(self.rect)
def TargPosForLine(self, position, mode):
try:
clicked_column = int((position.y() // 16)) * 16
clicked_row = int((position.x() // 16)) * 16
if clicked_column < 0:
clicked_column = 0
if clicked_row < 0:
clicked_row = 0
if (mode == "ForRect"):
return QRect(clicked_row, clicked_column, 16, 16)
elif (mode == "ForLine"):
return QPointF(clicked_row, clicked_column)
except Exception as e:
print("Error in TargPosForLine", e)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.scene = GraphicsSceneClass()
self.view=QGraphicsView(self.scene)
self.view.setMouseTracking(True)
self.view.setAcceptDrops(True)
self.view.setRenderHint(QPainter.HighQualityAntialiasing)
self.linePointerButton = QToolButton()
self.linePointerButton.setCheckable(True)
self.linePointerButton.setText("Drawline")
self.linePointerButton.setToolTip("Draw Track")
self.linePointerButton.clicked.connect(self.setPointerMode)
self.resizebutton = QToolButton()
self.resizebutton.setText("Resize")
self.resizebutton.setCheckable(True)
self.resizebutton.clicked.connect(self.resizepath)
self.widg=QWidget()
self.horizontal=QHBoxLayout()
self.horizontal.addWidget(self.view)
self.widg.setLayout(self.horizontal)
self.setCentralWidget(self.widg)
self.tool=self.addToolBar("Tool")
self.tool.addWidget(self.linePointerButton)
self.tool.addWidget(self.resizebutton)
def keyPressEvent(self, event):
try:
key = event.key()
if key == Qt.Key_Escape:
but = self.linePointerButton
self.scene.selectionMode = 1
but.setChecked(True)
except Exception:
print("Keypress is not working")
def setPointerMode(self):
try:
self.scene.selectionMode =2
except Exception:
print("Not able to change the selectionmode")
def resizepath(self):
self.scene.resizemode=1
self.scene.selectionMode = 1
self.linePointerButton.setChecked(False)
if __name__=="__main__":
import sys
app=QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
The path and the item and the shape from self.rect don't share the same coordinates system. So, when you want to remove the eraser from the line, the rect, you have to use a common coordinates system (for example, the one of you scene):
for item in self.collidingItems(self.rect):
new = item.mapToScene(item.path())-self.rect.mapToScene(self.rect.shape()) # translate the paths to the scene coords system
item.setPath(item.mapFromScene(new)) # translate the path from the scene coords system

Curses Python don't clean window when back in main menu

6 years ago they proposed an excellent solution on this issue, but my changes led to an unexpected result, the window does not clear when I call the submenu function and the main menu, help me understand what is wrong.
import curses
from curses import panel
from test_print import get_menu_list, get_timings, time_to_seconds, GetPageChoise,\
main_menu_items, list_of_themes_end, text_discription_get
page = GetPageChoise()
class Menu(object):
def __init__(self, items, stdscreen):
self.window = stdscreen.subwin(5,2)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
self.position = 0
self.items = items
self.items.append(('exit','exit'))
def navigate(self, n):
self.position += n
if self.position < 0:
self.position = 0
elif self.position >= len(self.items):
self.position = len(self.items)-1
def display(self):
self.panel.top()
self.panel.show()
self.window.clear()
while True:
self.window.refresh()
curses.doupdate()
for index, item in enumerate(self.items):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
msg = '%d. %s' % (index, item[0])
self.window.addstr(10+ index, 1, msg, mode)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord('\n')]:
if self.position == len(self.items)-1:
break
else:
self.items[self.position][1]()
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
class SubMenu(object):
def __init__(self, items, stdscreen):
self.window = stdscreen.subwin(5,2)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
self.position = 0
self.items = items
self.items.append(('exit','exit'))
def navigate(self, n):
self.position += n
if self.position < 0:
self.position = 0
elif self.position >= len(self.items):
self.position = len(self.items)-1
def display_sub(self):
while True:
self.window.refresh()
curses.doupdate()
for index, item in enumerate(self.items):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
next = 1
for disript in text_discription_get():
self.window.addstr(next, 1, disript)
next +=1
msg = '%d. %s' % (index, item[0])
self.window.addstr(10+ index, 1, msg, mode)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord('\n')]:
if self.position == len(self.items)-1:
break
else:
self.items[self.position][1]()
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
curses.curs_set(0)
submenu_items = [
('beep', curses.beep),
('flash', curses.flash)
]
submenu = SubMenu(sub_menu_items, self.screen) #Вывел конкретный подкаст, нужно изменить на выбор подкастов.
main_menu_items = [
('beep', curses.beep),
('flash', curses.flash),
('submenu', submenu.display_sub)
]
main_menu = Menu(main_menu_items, self.screen)
main_menu.display()
if __name__ == '__main__':
curses.wrapper(MyApp)
#Вывел меню, сделал выбор, нужно вывести Discription, сделать вызов плеера по выбору темы.
You can see how it looks at me at the GIF, the fact is that the proposed solution does not fit, since the submenu should display new content each time, depending on the choice.
gif how work this
Inserting a clear() after the function that shows the submenu worked for me:
class Menu(object):
...
def display(self):
...
if key in [curses.KEY_ENTER, ord('\n')]:
if self.position == len(self.items)-1:
break
else:
self.items[self.position][1]()
self.window.clear() # This will clear the main menu window every time an item is selected
You should also clear the screen before showing another window because the same thing could happen if your submenu was smaller than your main menu.
Alternatively, you could clear the window at the start of every loop, as you are already redrawing the list after each key press. This way you can update the items in the menu, and will not see parts of the old menu, as you would with your current program.

Categories