Using following code, I have the problems, that the buttons "Log Leeren" and "Auto Scroll" change their height, when I resize the window. They should be exactly one text-line high and the rest of the viewport should be used by the scrolledWindow
What do I need to change:
class ConsoleLogWindow(Gtk.Window):
def __init__(self, server):
self.log = server["log"];
Gtk.Window.__init__(self, title="Meteor Log von %s" % server["name"])
# self.set_icon_from_file("filename")
self.set_size_request(800,500)
table = Gtk.Table(3, 2, False)
self.add(table)
# Should be only one line of thext high
self.button_clear = Gtk.Button(label="Log Leeren")
self.button_scroll = Gtk.Button(label="Auto Scroll")
table.attach(self.button_clear, 2, 3, 1, 2)
table.attach(self.button_scroll, 0, 1, 1, 2)
# should take as much space as is available.
scrollWindow = Gtk.ScrolledWindow()
scrollWindow.set_hexpand(False)
scrollWindow.set_vexpand(True)
self.content_table = Gtk.Table(len(self.log)+1, 4, False)
# self.content_table is filled here.
scrollWindow.add(self.content_table)
table.attach(scrollWindow, 0, 3, 0, 1)
the window class is called in a function like:
def show_errors_menu(self, widget):
print ("Showing Error Menu")
win = ConsoleLogWindow(widget.get_node());
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Don't use Gtk.Table; it does not always respect the expand and align properties of its child widgets. Its replacement since GTK 3.0 has been Gtk.Grid. Using that, you only have to make sure that expand is set to true on the scrolled window and false on the buttons.
In the Qt side, at least, the frameworks consider for every widget a size attribute, a minimumSize attribute and a maximumSize attribute. Setting these three attributes to the same value for height and width makes them unresizable. Java's widgets have a explicit resizable attribute. I don't know how GTK3 prevents resizing, but doing some web search I came across this recipe which makes unresizable windows by extending and adding self.set_resizable(False) which is said to work. Give it a try and let me know!
Related
This is my code
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class Window(Gtk.Window):
def __init__(self):
super().__init__(title="GUi")
self.ui()
def ui(self):
self.connect("destroy", Gtk.main_quit)
button1 = Gtk.Button(label="Button 1")
button2 = Gtk.Button(label="Button 2")
grid = Gtk.Grid()
self.add(grid)
grid.attach(button1, 0, 0, 1, 1)
grid.attach(button2, 0, 3, 2, 2)
self.show_all()
window = Window()
Gtk.main()
and this is my output but I have mentioned the button 2 to appear in the 3rd column and gave it row and column span of 2 but both of these are not working as expected what am I doing wrong?
I am getting the impression that you are try trying to place the buttons beside each other with a space between them. check out this link where it mentions grid to get a better idea of what arguments for grid.attach(a,b,c,d,e) are.
(a) The child parameter is the Gtk.Widget to add.
(b) left is the column number to attach the left side of child to.
(c) top indicates the row number to attach the top side of child to.
(d, e) width and height indicate the number of columns that the child will span, and the number of rows that the child will span, respectively.
https://python-gtk-3-tutorial.readthedocs.io/en/latest/layout.html
you wont be able to put a space without using something like.
grid.set_row_spacing(20)
grid.set_column_spacing(20)
or maybe cell padding or button alignment. for more on that look at this link
https://athenajc.gitbooks.io/python-gtk-3-api/content/gtk-group/gtkgrid.html
keep in mind when thinking about sizing and positioning are inherited from classes. Positioning is tricky because you are can't really make a space between.
I'm trying to make a widget which contains many other widgets and I keep having problems with resizing the window: the widget keeps expanding even if I "tell" it not to. Here is my minimal example:
from PyQt5 import QtWidgets, QtGui, QtCore
class CustomWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout()
self.button1 = QtWidgets.QPushButton("Button A")
self.button2 = QtWidgets.QPushButton("Button B")
self.label1 = QtWidgets.QLabel("Long label that can span multiple columns")
self.layout.addWidget(self.button1, 0, 0)
self.layout.addWidget(self.button2, 0, 1)
self.layout.addWidget(self.label1, 1, 0, 1, 2)
self.setLayout(self.layout)
class App(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.cw = CustomWidget()
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.cw)
self.setLayout(self.layout)
self.show()
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create("Fusion"))
app = QtWidgets.QApplication([])
win = App()
status = app.exec_()
This code does work however if I resize the window then all the buttons and labels get spread out over the screen which is not what I want.
I've tried:
Setting a fixed size: doesn't work because the label text can be different lengths and I want the widget to resize accordingly (but stay as small as possible)
self.setFixedSize(self.size()) doesn't do anything and sometimes makes it worse
self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) or any other size policy seems to do nothing
TL;DR I want my widget to shrink even if there's empty space but I don't want to set a fixed size.
EDIT:
I have partially solved the problem by passing in alignment=QtCore.Qt.AlignLeft to all the self.layout.addWidget calls. It doesn't totally get rid of the problem however it may be a step in the right direction.
If you want to keep those widgets as small as possible, you can add a row and column stretch to the layout, set for a row/column index greater than the most bottom-right layout coordinate used.
In your case, you have two rows and two columns, so it's enough to set the stretch for the third row and column:
self.layout.setColumnStretch(2, 1)
self.layout.setRowStretch(2, 1)
Obviously, you can set it for a very high index, so that if you have to add more widgets you don't have to care about it.
If you want to keep those widgets in the center, just add them starting from the second row and column and set the row/column stretch for the first row/column too:
self.layout.setColumnStretch(0, 1)
self.layout.setRowStretch(0, 1)
self.layout.addWidget(self.button1, 1, 1)
self.layout.addWidget(self.button2, 1, 2)
self.layout.addWidget(self.label1, 2, 1, 1, 2)
self.layout.setColumnStretch(3, 1)
self.layout.setRowStretch(3, 1)
Note that you can also use the size policy, but you have to use Maximum, not Minimum, and you also need to add widgets with the correct alignment.
I got same issue. I resolved the issue by setting the values of minimum and maximum size to equal like both to 100
If you want to shrink the widget set minimum to 0 and set maximum value to the size you want start the display. It will not expand but shrink
From what you are describing it seems you just don't want to use a layout.
Make a widget with a layout to hold the buttons and label. Place this widget in the main window without using a layout, instead place with setGeometry.
Something like this,
from PyQt5 import QtWidgets, QtGui, QtCore
class CustomWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.resize(400, 100)
# Create a widget to hold your buttons
self.fixwidget = QtWidgets.QWidget(self)
self.layout = QtWidgets.QGridLayout()
self.button1 = QtWidgets.QPushButton("Button A")
self.button2 = QtWidgets.QPushButton("Button B")
self.label1 = QtWidgets.QLabel("Long label that can span multiple columns")
self.layout.addWidget(self.button1, 0, 0)
self.layout.addWidget(self.button2, 0, 1)
self.layout.addWidget(self.label1, 1, 0, 1, 2)
# set the layout inside the widget
self.fixwidget.setLayout(self.layout)
# place the widget with setGeometry
height = self.fixwidget.sizeHint().height()
width = self.fixwidget.sizeHint().width()
xpos, ypos = 5, 5
self.fixwidget.setGeometry(QtCore.QRect(xpos, ypos, width, height))
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create("Fusion"))
app = QtWidgets.QApplication([])
win = CustomWidget()
win.show()
status = app.exec_()
Notice that not using a layout is, in most cases, not advised as it makes managing the window harder.
I have currently got a PyQt5 application which is quite simple (just one button). I'd like for it to have vibrancy, so I've ported ObjC vibrancy code to Python. My vibrancy code is as follows:
frame = NSMakeRect(0, 0, * self.get_screen_size()) # get_screen_size returns the resolution of the monitor
view = objc.objc_object(c_void_p=self.winId().__int__()) # returns NSView of current window
visualEffectView = NSVisualEffectView.new()
visualEffectView.setAutoresizingMask_(NSViewWidthSizable|NSViewHeightSizable) # equivalent to: visualEffectView.autoresizingMask = NSViewW...
visualEffectView.setFrame_(frame)
visualEffectView.setState_(NSVisualEffectStateActive)
visualEffectView.setMaterial_(NSVisualEffectMaterialDark)
visualEffectView.setBlendingMode_(NSVisualEffectBlendingModeBehindWindow)
window = view.window()
window.contentView().addSubview_positioned_relativeTo_(visualEffectView, NSWindowBelow, None)
# equal to: [window.contentView addSubview:visualEffectView positioned:NSWindowBelow relativeTo:nul]
window.setTitlebarAppearsTransparent_(True)
window.setStyleMask_(window.styleMask() | NSFullSizeContentViewWindowMask) # so the title bar is also vibrant
self.repaint()
All I'm doing to draw a button is: btn = QPushButton("test", self)
self is a class inherited from QMainWindow and everything else should be fairly unimportant.
Behaviour with the window.contentView().addSubview... line commented out (no vibrancy)
Behaviour without it commented out (with vibrancy)
Thanks!
The UI elements are actually drawn, but the NSVisualEffectView is covering them.
I fixed that issue by adding another view QMacCocoaViewContainer to the window.
You'll also need to set the Window transparent, otherwise the widgets will have a slight background border.
If you use the dark vibrant window also make sure to set appearance correctly, so buttons, labels etc. are rendered correctly.
frame = NSMakeRect(0, 0, self.width(), self.height())
view = objc.objc_object(c_void_p=self.winId().__int__())
visualEffectView = NSVisualEffectView.new()
visualEffectView.setAutoresizingMask_(NSViewWidthSizable|NSViewHeightSizable)
visualEffectView.setWantsLayer_(True)
visualEffectView.setFrame_(frame)
visualEffectView.setState_(NSVisualEffectStateActive)
visualEffectView.setMaterial_(NSVisualEffectMaterialUltraDark)
visualEffectView.setBlendingMode_(NSVisualEffectBlendingModeBehindWindow)
visualEffectView.setWantsLayer_(True)
self.setAttribute(Qt.WA_TranslucentBackground, True)
window = view.window()
content = window.contentView()
container = QMacCocoaViewContainer(0, self)
content.addSubview_positioned_relativeTo_(visualEffectView, NSWindowBelow, container)
window.setTitlebarAppearsTransparent_(True)
window.setStyleMask_(window.styleMask() | NSFullSizeContentViewWindowMask)
appearance = NSAppearance.appearanceNamed_('NSAppearanceNameVibrantDark')
window.setAppearance_(appearance)
Result:
I've googled around but I'm not able to find a solution to my problem.
I have a QTableWidget with 2 columns and what I'm trying to do is to make them visible to the whole widget without the horizontal scrollbar to appear.
With a picture it should be all clear:
I have used Qt Designer to create the UI and some code to fill all the widgets and other stuff.
So, first I resized th2 2 columns to the content with:
self.statTable.resizeColumnToContents(0)
self.statTable.resizeColumnToContents(1)
and it works, but then the Widget is not resizing to the 2 columns width.
This has a very easy solution in PyQt5. All you need to do is set the size adjust policy on the table when initialising the UI, and it will automatically resize to fit the contents. This can either be done via Qt Designer (in the QAbstractScrollArea section of the Property Editor), or programmatically, like this:
self.statTable.setSizeAdjustPolicy(
QtWidgets.QAbstractScrollArea.AdjustToContents)
You then just need to do:
self.statTable.resizeColumnsToContents()
whenever the table is re-populated.
For PyQt4, everything has to be calculated manually, and a few hacks are also required to get completely consistent results. The demo script below works okay for me, but YMMV:
import random
from PyQt4 import QtCore, QtGui
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.table = QtGui.QTableWidget(5, 2, self)
self.button = QtGui.QPushButton('Populate', self)
self.button.clicked.connect(self.populate)
layout = QtGui.QGridLayout(self)
layout.addWidget(self.table, 0, 0)
layout.addWidget(self.button, 1, 0)
layout.setColumnStretch(1, 1)
def populate(self):
words = 'Red Green Blue Yellow Black White Purple'.split()
length = random.randint(2, len(words))
self.table.setRowCount(random.randint(3, 30))
for column in range(self.table.columnCount()):
for row in range(self.table.rowCount()):
item = QtGui.QTableWidgetItem(' '.join(
random.sample(words, random.randint(1, length))))
self.table.setItem(row, column, item)
self.table.setVisible(False)
self.table.verticalScrollBar().setValue(0)
self.table.resizeColumnsToContents()
self.table.setVisible(True)
self.setTableWidth()
def setTableWidth(self):
width = self.table.verticalHeader().width()
width += self.table.horizontalHeader().length()
if self.table.verticalScrollBar().isVisible():
width += self.table.verticalScrollBar().width()
width += self.table.frameWidth() * 2
self.table.setFixedWidth(width)
def resizeEvent(self, event):
self.setTableWidth()
super(Window, self).resizeEvent(event)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(700, 150, 800, 400)
window.show()
sys.exit(app.exec_())
For the autoadjust settings on the table widget in Qt Designer, you canlook in the object inspector for the table widget you can drill down to it as shown below.
(PyQt5)
The issue for me is that my cells in the right-most column are multi-line (QPlainTextEdit), and I wanted word-wrapping... but I also wanted this right-most column to extend to fill the parent container.
It seems you can do everything you need in PyQt5 designer, in the Property editor for your QTableView:
in the "QTableView" section check "wordWrap"
in the "QAbstractScroll" section check "AdjustToContents" (as mentioned by Crap Phone)
in the "Header" section check "horizontalHeaderStretchLastSection"
This then generates the following sort of code:
self.history_table_view.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow)
self.history_table_view.horizontalHeader().setStretchLastSection(True )
"word wrap = True" appears to be the default setting, so nothing is shown, but it would be this:
self.history_table_view.setWordWrap(True)
Use your_tablewidget.resizeColumnsToContents() every single time after you call your_tablewidget.setItem(). You don't need any other setting.
you know just try, tableWidget.resize(1200, 600) *you can change resolution but it is your answer...
I want to create a window where is Qt3DWindow in the back and some QPushButtons above it. However only Qt3DWindow animation is shown and QPushButtons are not seen. I would also like to have Qt3DWindow functional and QPushButtons as well (So I can click on the buttons or 3D animation behind). Buttons are only seen when I set Qt3DWindow transparency to lower value. Of course in that case buttons are only seen but not functional.
class MainWindow(QMainWindow):
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.window = Window() # Qt3DExtras.Qt3DWindow
self.container = self.createWindowContainer(self.window)
self.buttons = Buttons()
self.layout().addWidget(self.buttons.view) # QtWidgets.QGraphicsView
self.layout().addWidget(self.container)
QWidget::createWindowContainer() will handle the geometry of the window however it does change the fact that the managed window still overlays the window that contains the widget. So any child of that widget will not be visible as it will be obscured by the Qt3DWindow.
Only viable alternative is move the widgets you want to overlay into their own window and handles it's geometry yourself.
Or use a Scene3D inside a QDeclarativeWidget but that will affect performance.
As per the comment, QMainWindow uses its own layout type which is responsible for a large part (most) of its functionality -- dock widgets, toolbars etc.
Rather than just add widgets to that layout you need to create your own widget hierarchy and pass that to QMainWindow::setCentralWidget.
If you want the Buttons to lie in front of the container you can probably use a QGridLayout.
So, you could try something like (untested)...
class MainWindow(QMainWindow):
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.window = Window() # Qt3DExtras.Qt3DWindow
self.container = self.createWindowContainer(self.window)
self.buttons = Buttons()
central_widget = QWidget()
central_widget_layout = QGridLayout()
central_widget_layout.addWidget(self.container, 0, 0, 2, 1)
central_widget_layout.addWidget(self.buttons.view, 0, 0, 1, 1)
central_widget.setLayout(central_widget_layout)
setCentralWidget(central_widget)