How can I make a Lollypop like sidebar in Gtk? - python

I have been trying to make a simple Gtk application that includes a Side Bar similar to the side bar in the Lollypop music player (as seen here https://youtu.be/2IhJCrKz3N4 ), I don't which layout container is the best for such a thing , I tried Gtk.Box with vertical orientation but the result similar to what I want. can someone suggest a better solution for this and a way to place this side bar on the window while keeping it's side fixed.

For new developer it may be difficult to dig into source code of some software, but it is really helps you in long run. Please check out source code of Lollypop at https://gitlab.gnome.org/World/lollypop for functionality you are taking about.
Apart from that, in below code I try to give you head start from what I understood from your question.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Side Bar")
self.hbox = Gtk.HBox();
self.vbox = Gtk.VBox();
self.button1 = Gtk.Button(label="1")
self.button1.connect("clicked", self.on_button_clicked)
self.button2 = Gtk.Button(label="2")
self.button2.connect("clicked", self.on_button_clicked)
self.button3 = Gtk.Button(label="3")
self.button3.connect("clicked", self.on_button_clicked)
self.button4 = Gtk.Button(label="4")
self.button4.connect("clicked", self.on_button_clicked)
self.vbox.add(self.button1);
self.vbox.add(self.button2);
self.vbox.add(self.button3);
self.vbox.add(self.button4);
self.entry = Gtk.Entry();
self.entry.set_text("1");
self.hbox.add(self.vbox);
self.hbox.add(self.entry);
self.add(self.hbox);
self.maximize()
def on_button_clicked(self, widget):
self.entry.set_text(widget.get_label());
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Implementation of Lollypop may be very different from above one, because it may need to handle many more things like responsive size of button while resizing, look and feel with different themes, etc.
ADVISE: Keep digging and contributing to open source software to learn more.

You may run GTK_DEBUG=interactive your-app to use gtk-inspector. It lets you examine an existing user-interface, like lollypop, and check how the widgets are bound together.
Please read the interactive debugging section of the documentation.
For more detail, as Mathan Tilva said, you can give a look to the source code.

Related

How do I make a GTK 2 list with multiple selection?

In a GTK 3 release, the ListBox widget added supported for multiple elements being selected from the list:
I'd like to achieve the same effect with GTK 2. I'm considering using a ScrolledWindow with a VBox of CheckButton's. I fear it's not going to look very good though; like this, but with a scrollbar:
Does anyone know a good way to emulate the functionality in the first image using GTK 2?
It turns out there was a method of doing just this buried in the documentation! In fact, you should find it all the way back to GTK 2.0, but the selection constant might have had a different name (SELECTION_MULTI).
The widget looks like this:
The color scheme is inherited from my GNOME theme, so don't mind the window styling too much. This widget works with both Ctrl and Shift keys. It doesn't automatically have multiple selection just clicking on the different items.
Here's the (Python 2) MWE I made for this:
import gtk
class UI(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.set_position(gtk.WIN_POS_CENTER)
self.set_default_size(250, 150)
store = gtk.ListStore(str)
for i in range(7):
# The list notation here is odd, but required.
store.append(["Item %d" % i])
tree_view = gtk.TreeView()
tree_view.set_model(store)
# The view can support a whole tree, but we want just a list.
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn("Multiple Selection", renderer, text=0)
tree_view.append_column(column)
# This is the part that enables multiple selection.
tree_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
scrolled_tree = gtk.ScrolledWindow()
scrolled_tree.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
scrolled_tree.add_with_viewport(tree_view)
self.add(scrolled_tree)
def main():
win = UI()
win.connect("destroy", gtk.main_quit)
win.show_all()
gtk.main()
if __name__ == "__main__":
main()

wxPython - Button size being ignored on OSX

I'm taking the first steps to move from .NET to Python but I'm already having a few headaches regarding the GUI design.
For some reason, passing the size attribute to a wx.Button seems to be kind of ignored. And I say "kind of" because the actual space seems to change but the actual button keeps occupying the same space:
import wx
class Example(wx.Frame):
def __init__(self, *args, **kwargs):
super(Example, self).__init__(*args, **kwargs)
self.InitUI()
def InitUI(self):
self.SetSize((800, 600))
self.SetTitle('Main Menu')
self.Centre()
self.Show(True)
''' Fill the form '''
self.lblUsername = wx.StaticText(self, size=(80, -1), pos=(20,20), label="Username:" )
self.txtUsername = wx.TextCtrl(self, size=(140, -1), pos=(100,20), style=wx.TE_PROCESS_ENTER)
self.lblPassword = wx.StaticText(self, size=(80, -1), pos=(20,50), label="Password:" )
self.txtPassword = wx.TextCtrl(self, size=(140, -1), pos=(100,50), style=wx.TE_PROCESS_ENTER)
self.btnOK = wx.Button( self, label="OK", pos=(260, 16), size=(50,50))
self.btnOK.Bind(wx.EVT_BUTTON, self.onClickOK)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText('Ready')
def onClickOK(self, e):
print "Button triggered"
def main():
ex = wx.App()
Example(None)
ex.MainLoop()
if __name__ == '__main__':
main()
No matter what size I set, the Button won't stretch (it will be centered as if all the space was actually being used, but will still be small).
Can anyone spot what am I doing wrong?
This is a limit imposed by OSX. The way the native button widget is drawn only allows it to be stretched horizontally, and the vertical size is fixed. Or rather, as you've discovered, the widget itself can be larger than normal vertically, but it will only draw itself at a fixed height within that space. It seems less neccessary with modern versions of OSX, but if you look at buttons in OSX from a few years ago you can probably see why this is so. The esthetic graphical effect of the "tic-tack" or "capsule" buttons would be totally ruined if they were a non-standard vertical size, causing the images used to draw the buttons to be stretched. wxWidgets follows the native plaform look and feel standards where possible, in this case it happens that Apple's standard is imposed upon us and wx can't offer the same level of flexibility that it usually does.
You do have some options however if you really want taller than normal buttons. The native widgets have a few different standard sizes, which you can select using the SetWindowVariant method, although I don't think the variants would get as tall as you want. Or you could use a generic button widget instead of a native one, such as wx.lib.buttons.ThemedGenButton.
Same problem in my little Software EventSoundControl.
Just a workaround: Use a multiline label and sizes of wxButton will work as desired!
If you want the button to stretch when you resize the frame, then you cannot use static sizes and positioning. You will need to put your widgets in a sizer. Then the sizer will manage the position / size of the widget(s) as you change the size of the frame. There are many examples on the wxPython wiki that demonstrate how to use sizers. You might also find the following tutorial helpful:
http://zetcode.com/wxpython/layout/

Gtk.TextView very slow with many TextTags

I need to continually change the styling of parts of a TextView to do syntax highlighting. However with about 1,000 Gtk.TextTags it becomes extremely slow. I don't want to use a Gtk.SourceView because I want to customize styling myself. It seems rather odd that 1,000 tags is enough to make the TextView choppy since a word processing document might have that many.
This code gives an example of the slowness. With 1,000s of characters it starts taking about half a second to update the tags.
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(600, 400)
self.scrolledwindow = Gtk.ScrolledWindow()
self.textview = Gtk.TextView()
buffer = self.textview.get_buffer()
buffer.create_tag("tag", background="orange")
buffer.connect("end-user-action", self.action)
self.scrolledwindow.add(self.textview)
self.add(self.scrolledwindow)
def action(self, buffer):
start = buffer.get_start_iter()
veryend = buffer.get_end_iter()
buffer.remove_all_tags(start, veryend)
end = buffer.get_iter_at_offset(1)
for i in range(len(buffer.get_text(start, veryend, False))//2+1):
buffer.apply_tag_by_name("tag", start, end)
start.forward_chars(2)
end.forward_chars(2)
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Can I speed this up? Are there any workarounds?
If someone ever finds this question via google let me tell you that the problem here is the removing of all tags and adding it again. This is of course a very time consuming operation and shouldn't be coded this way.

How to create full transparency in a QTextEdit

I have been trying for many days to figure out a way to create a transparent Qtextedit with opaque text. Because the term "transparency" is often ambiguous, I define Qtextedit"transparency" as being able to see the text in the Qtextedit overlaid upon whatever is directly behind the main window (such as the desktop background, windows media player etc.) If possible I would like to be able to set the transparency at various levels and cross system compatible, but this is not required.
I am an extreme beginner, as I have only been using pyqt4 for 3 weeks and python 3.x for a few months and this is all the experience with programming that I have obtained in my existence. I have been attempting to decipher the Pyqt documentation with regard to this matter, but it is written in a way that seems to assume that one has been a gui programer for decades, not to mention having knowlege of C++. Furthermore, when this question is asked online it never seems to be resolved in way that is either: a) well documented or b) generalizable
This is very surprising because it seems like a basic operation that people would want to do
This solution works but doesn't seem to be directly useful for anything but displaying transparent images. I also don't really understand it all that well, as simply changing the base class from QWidget to QMainWindow makes the whole thing fail
http://www.loopbacking.info/blog/2008/07/11/transparent-windows-howto/
The following link embodies the common ways people suggest to solve problems similar to this, their pitfalls and why they don't work, but unfortunately they use the C++ version of Qt and are also a bit advanced for my skills at this point.
http://www.qtcentre.org/threads/18072-How-to-set-Qt-window-transparent
My system is windows 7 ultimate 32 bit on a dell latitude d830 with a Quadro NVS 140 whose driver version is current as of this post (Verde 275.33) My version of Pyqt is 4.8 (PyQt-Py3.2-x86-gpl-4.8.5-1.exe Windows 32 bit installer) I am also using Python 3.2.1 (Open Source version)
A basic example of my code lies beneath with the relevant (and failed) lines commented out:
When I tried the commented out code the color I generally just saw blackness. Also, when I resized my windows the darkness would randomly change intensity and the display of the main window seemed to get corrupted when maximized.
I would greatly appreciate any help on this matter!
import sys
import PyQt4
from PyQt4 import QtGui, QtCore
class Transparent(QtGui.QMainWindow):
def __init__(self,parent = None):
QtGui.QMainWindow.__init__(self,parent)
self.initialize()
def initialize(self):
#self.colorset(self,'Window',200,255,100,20)
#self.colorset(self,'Base',200,255,100,20)
#self.setBackgroundRole(QtGui.QPalette.Base)
#self.setAttribute(QtCore.Qt.WA_NoSystemBackground)
#self.setAutoFillBackground(True)
#self.mask()
self.setWindowTitle("Chernobyl-like Failure")
self.answerlabel = QtGui.QLabel('Text Response Display')
self.answerlabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
self.answerlabel.setMinimumHeight(25)
self.questionlabel = QtGui.QLabel("Question:")
self.questionlabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
self.questionbox = QtGui.QLineEdit()
self.questionbox.setMinimumWidth(500)
self.askbutton = QtGui.QPushButton("Ask it!")
self.historybox = QtGui.QTextEdit('Question & Answer history will be displayed here')
self.historybox.setReadOnly(True)
#self.colorset(self.historybox,'Base',200,255,100,127)
self.grid = QtGui.QGridLayout()
widgetlist = [['answerlabel',0,0,1,3],['questionlabel',1,0,1,1],
['questionbox',1,1,1,1],['askbutton',1,2,1,1],['historybox',2,0,1,3]]
for widget in widgetlist:
self.grid.addWidget(eval("self.{0}".format(widget[0])),*widget[1:])
self.centralwidget = QtGui.QFrame()
self.centralwidget.setFrameStyle(QtGui.QFrame.Box|QtGui.QFrame.Raised)
self.centralwidget.setLineWidth(5)
self.centralwidget.setLayout(self.grid)
#self.colorset(self.centralwidget,'Base',200,255,100,127)
self.setCentralWidget(self.centralwidget)
def colorset(self,widget,part,h,s,l,a):
pal = widget.palette()
color = QtGui.QColor()
color.setHsl(h,s,l,a)
pal.setColor(eval('QtGui.QPalette.{0}'.format(part)),color)
widget.setPalette(pal)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main_window = Transparent()
main_window.show()
sys.exit(app.exec_())
To make your main window transparent, you have to set the Qt.WA_TranslucentBackground attribute (using setAttribute(Qt.WA_TranslucentBackground)). Under Windows, you also must set the Qt.FramelessWindowHint attribute on your main window. According to the docs, however, "The user cannot move or resize a borderless window via the window system." So, if you want that functionality, you have to implement it manually. Here is a thread giving an example of that in C++.
Once you have a transparent MainWindow you can control the opacity of it and any child widgets by setting the background color to an RGBA value. Here is a dumb example,
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
frame = QtGui.QFrame(parent=self)
frame.setStyleSheet("QFrame {background: rgba(0,255,0,20%)}")
box=QtGui.QHBoxLayout()
edit = QtGui.QTextEdit()
edit.setStyleSheet("background: rgba(0,0,255,20%)")
box.addWidget(edit)
edit2=QtGui.QTextEdit()
edit2.setStyleSheet("background: rgb(255,0,0)")
box.addWidget(edit2)
frame.setLayout(box)
pushbutton = QtGui.QPushButton('Quit')
pushbutton.clicked.connect(self.close)
box.addWidget(pushbutton)
self.setCentralWidget(frame)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
app.exec_()

wxpython systray icon menu

I'm designing an application that I want to run in the background. There isn't any user interaction necessary, so I want the app to run invisibly save for a systray icon. I want that icon to have a menu that just opens the config/help files in notepad. Could someone point me in the right direction or provide an example?
You can probably do this more cleanly but I have using some samples a while back I was able to create myself a class to handle the basic contruction of a taskbar icon.
TaskBarIcon.py
import wx
ID_SHOW_OPTION = wx.NewId()
ID_EDIT_OPTION = wx.NewId()
class Icon(wx.TaskBarIcon):
def __init__(self, parent, icon, tooltip):
wx.TaskBarIcon.__init__(self)
self.SetIcon(icon, tooltip)
self.parent = parent
self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnLeftDClick)
self.CreateMenu()
def CreateMenu(self):
self.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnPopup)
self.menu = wx.Menu()
self.menu.Append(ID_SHOW_OPTION, '&Show Option 1')
self.menu.Append(ID_EDIT_OPTION, '&Edit Option 2')
self.menu.AppendSeparator()
self.menu.Append(wx.ID_EXIT, 'E&xit')
def OnPopup(self, event):
self.PopupMenu(self.menu)
def OnLeftDClick(self, event):
if self.parent.IsIconized():
self.parent.Iconize(False)
if not self.parent.IsShown():
self.parent.Show(True)
self.parent.Raise()
Within your Frame's init(), add the two lines below:
self.TrayIcon = tbi.Icon(self, wx.Icon("C:\\YourIcon.png", wx.BITMAP_TYPE_PNG), "ToolTip Help Text Here")
self.Bind(wx.EVT_ICONIZE, self.OnIconify)
And now just add this function to your frame and you should be set:
def OnIconify(self, event):
self.Hide()
Just remember to edit the items in the Icon class to suit your needs.
Have you considered running this application as a windows service? Many users will consider a system tray icon with little to no functionality a nuisance. You could still provide links to help/config files as a start menu entry.
The python win32 extensions package should have support for python services.
Of course, there are still reasons why you may want to run this as a system tray icon. I'm sorry that I don't have any experience with that.
You want the wx.TaskBarIcon:
http://docs.wxwidgets.org/stable/wx_wxtaskbaricon.html
The wxPython Demo has example code you can look at.

Categories

Resources