How can I detect a mouse click on a custom wx.Panel? - python-3.x

I am pretty new at both Python and wxPython. Anyway, after having followed the official tutorial where they explain how to do a basic text editor, I decided to go ahead and write a real text editor.
Now, my text editor consists of a MainWindow (which inherits from wx.Frame), which in turn contains a Notebook (inheriting from wx.Notebook) which in turn contains several tabs (a custom class inheriting from wx.Panel).
If I didn't misunderstand, events in wxPython can be detected and bounded to specific objects via the Bind() function.
Here's my custom panel class:
class TabContent(wx.Panel) :
def __init__(self, parent) :
# Calls the constructor for wx.Panel
wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
# Creates a vertical sizer
sizer = wx.BoxSizer(wx.VERTICAL)
# Creates an empty multiline wx.TextCtrl
textArea = wx.TextCtrl(self, style = wx.TE_MULTILINE)
# Adds the text area to the sizer
sizer.Add(textArea, 1, wx.EXPAND | wx.ALL, 2)
# Sets the previously created sizer as this panel's sizer
self.SetSizer(sizer)
# Sets up events
self.Bind(wx.EVT_RIGHT_DOWN, self.onMouseLeftClicked)
def onMouseLeftClicked(self, event) :
print("Left button of the mouse was clicked\n")
I'd like to be able to detect right clicks on the tab itself (for example I could open a menu or just print something for the sake of testing wxPython functions). However, clicking with the mouse does not print anything. Any idea why?
By the way, I am on ArchLinux, using PyCharm Community Edition 2016.2.3, Python 3.5.2 and wxpython 3.0.2.

The event was actually being caught, but only on the very thin border of the tab.
Solved by putting the event handler in the Notebook class.

Related

Is there a way to resize a QAction

The QAction inside a QToolBar is away bigger than the icon I am using (16x16 or 32x32). How to resize a QAction to fit an icon without extra space. I tried to subclass, but I could find a method for the QAction to resize.
class MyAction(QAction):
def __init__(self)
super().__init__()
I tried to use setIconSize(QSize(32,32)), but it is not affecting the QAction it self. I believe this is related to the app stylesheet I am using, but I don't want to change that.
My current solution is to use a QToolButton, and addWidget inside the QToolBar(), is there better way ?
I am simply using a QMainWindow:
class Window(QMainWindow):
def__init__(self)
super().__init__()
self._Bar_1 = self.addToolBar('bar_1')
self._Bar_1.setIconSize(QSize(41, 41))
act1 = QAction(QIcon(r'icons\exit.png'), 'Exit', self)
self._Bar_1.addAction(act1)
I can't take a snapshot cause I need to hover or click the action to show its size, but it looks like this. I believe it is related to the stylesheet I am using:
This is ascrren shot I could get. notice, when hovering or press on the QAction in the first ToolBar, the action is seems too big for the icon inside ! Hope it helps
I am using the qt_material , find the link https://github.com/UN-GCPDS/qt-material

Qt Designer make widget overlap another widget in layout

I want to make 3 window button like above picture (similar Google Chrome) use Qt Designer and PyQt.
I want 3 buttons overlap right side of TabWidget.
But I only can overlap the Button on TabWidget when break layout like the picture.
When I set any layout, every widget can not overlap on each other.
So can I overlap when set layout? Thanks.
This is the layout I want
It similar Google Chrome's layout
This cannot be done in creator/designer, and can only be achieved using setCornerWidget() from your code.
Since only one widget can be set for each corner, you have to create a QWidget that acts as a container, then add the buttons to it.
class Test(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# ...
self.createButtons()
def createButtons(self):
# create the container and its layout
self.buttonContainer = QtWidgets.QWidget()
buttonLayout = QtWidgets.QHBoxLayout(self.buttonContainer)
# remove margins around the layout and set a minimal spacing between
# the children widgets
buttonLayout.setContentsMargins(0, 0, 0, 0)
buttonLayout.setSpacing(1)
# QToolButtons are usually better for this, as QPushButtons tend
# to expand themselves
self.minimizeButton = QtWidgets.QToolButton(text='_')
self.maximizeButton = QtWidgets.QToolButton(text='o')
self.closeButton = QtWidgets.QToolButton(text='x')
buttonLayout.addWidget(self.minimizeButton)
buttonLayout.addWidget(self.maximizeButton)
buttonLayout.addWidget(self.closeButton)
# set the container as the corner widget; as the docs explain,
# despite using "TopRightCorner", only the horizontal element (right
# in this case) will be used
self.tabWidget.setCornerWidget(
self.buttonContainer, QtCore.Qt.TopRightCorner)

Cannot position button content neither with anchor nor with justify

I have dynamic button label, which changes everytime you click it. The problem is, when text on the button changes, the same goes with button width. For this reason I set fixed width for my button.
After that, another problem appeared. Content is centered within button, so on every change image and label move a bit. For this reason I tried to position everything to the left side to reduce content trembling.
I looked through docs and found that button widget supports anchor option to position content. However, when I try it, I'm getting error:
_tkinter.TclError: unknown option "-anchor"
I found another option, justify, but result is the same:
_tkinter.TclError: unknown option "-justify"
Anyone knows how to deal with it? I'll share my code with you:
self.btnServiceIo = ttk.Button(
top_buttons_frame,
text="Usługa automatyczna",
image=self.ioBtnImg_off,
compound=tk.LEFT,
width=30,
justify=tk.LEFT,
anchor='w')
self.btnServiceIo.pack(side=tk.LEFT)
self.btnServiceIo.bind("<ButtonRelease>", self.IObuttonToggle)
(I don't use justify and anchor at the same time, I just posted them together to show you the way I'm using it)
I'll post the picture of my app for your attention. My client would like to have not only toggle image which states the status of some service, but also text information nearby.
For ttk buttons you can set the anchor option in the ttk style, see the anchor entry on this page.
So for example:
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
root = tk.Tk()
s = ttk.Style()
s.configure('TButton', anchor=tk.W)
buttonImage = Image.open('test.png')
buttonPhoto = ImageTk.PhotoImage(buttonImage)
btnServiceIo = ttk.Button(
root,
text="Usługa automatyczna",
image=buttonPhoto,
compound=tk.LEFT,
width=30)
btnServiceIo.pack(side=tk.LEFT)
root.mainloop()
Answer from #fhdrsdg was almost perfect, but it messed with some of my simple buttons with text only, centered in the button. I had to make dedicated style for my button as following:
# Access ttk style object
s = ttk.Style()
# Set dedicated style for button, derived from main button class
s.configure('service-io.TButton', anchor=tk.W)
self.ioBtnImg_off = tk.PhotoImage(file='../img/io.png')
self.ioBtnImg_on = tk.PhotoImage(file='../img/io_on.png')
self.btnServiceIo = ttk.Button(
top_buttons_frame,
text="Usługa automatyczna",
image=self.ioBtnImg_off,
compound=tk.LEFT,
width=30,
style='service-io.TButton' # use dedicated style
)

how can I create a menuBar using tkinter in python

I really hope that you understand the following question, because I wasn't sure how to ask this question so I hope you can help me, if not let me now
I want to make a program to practise my python programming skill. I want to make a store program where an employee could input items with the price, and where he could sell the items. I want to make it that one “page” is the items input an another “page” is the sell page. To so that I want to make a menu bar where the employee could press on the let's say input button and go to input items page, but when he wants to sell items he presses on the sell button and then he goes to the sell page but only the screen changes, not that there comes another tab/window.
I really hope I explained my problem good enough
Thanks in advance!!
Based on your comments to the question, it appears your main problem is that you don't know how to make a menubar, so I will address that part of the question.
Every top level window (instances of Tk and Toplevel) have a menu attribute that can be set to an instance of a Menu object. This menu can itself have dropdown menus, and that combination is what makes a menubar.
In order to make this work you must first create the menu, and then associate that menu with the window.
import tkinter as tk
root = tk.Tk()
self.menubar = tk.Menu()
root.configure(menu=self.menubar)
To create the sub-menus you must do something very similar. First, create a new Menu instance, then associate it with the menubar using add_cascade. Typically, the menu will be a child of the menubar. You use the add_command method to add items to the sub-menu.
In your case, you might want to create a "View" menu with items for switching between "Input" and "Sell". It would look something like this:
viewMenu = tk.Menu(self.menubar)
self.menubar.add_cascade(label="View", menu=viewMenu)
viewMenu.add_command(label="Input", command=self.switch_to_input)
viewMenu.add_command(label="Sell", command=self.switch_to_sell)
Example
Here is a complete working example. To keep it simple and on topic it doesn't actually switch pages. Instead, it just displays the "page" in a label.
import tkinter as tk
class MenuExample:
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(self.root, width=25)
self.label.pack(side="top", fill="both", expand=True, padx=20, pady=20)
self._create_menubar()
def _create_menubar(self):
# create the menubar
self.menubar = tk.Menu(self.root)
self.root.configure(menu=self.menubar)
# File menu
fileMenu = tk.Menu(self.menubar)
self.menubar.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="Exit", command=self.root.destroy)
# View menu
viewMenu = tk.Menu(self.menubar)
self.menubar.add_cascade(label="View", menu=viewMenu)
viewMenu.add_command(label="Input", command=self.switch_to_input)
viewMenu.add_command(label="Sell", command=self.switch_to_sell)
def switch_to_input(self):
# put the code to switch to the input page here...
self.label.configure(text="you clicked on View->Input")
def switch_to_sell(self):
# put the code to switch to the sell page here...
self.label.configure(text="you clicked on View->Sell")
app = MenuExample()
tk.mainloop()

PyQt adding a scrollbar to my main window

I want to add a scrollbar to my main window
Here's a simplified version of my code since mine is too long.
class Main(QtGui.QWidget):
def __init__(self):
super(Main, self).__init__()
verticalLayout = QtGui.QVBoxLayout()
self.setGeometry(0,0,400,400)
self.setLayout(verticalLayout)
label_1 = QtGui.QLabel("label 1")
self.verticalLayout.addWidget(label_1)
...(many more that exceed my computer screen)
so I've been reading a lot of posts about scrollbars but I'm still not quite sure as to how to implement it.
Within your main window, you need to create a Scroll Area.
http://pyqt.sourceforge.net/Docs/PyQt4/qscrollarea.html

Resources