scaledToHeight() does not scale to height - PyQt5 - python-3.x

I'm trying to render my image, but scaled to the height of the current window and keeping with aspect ratio.
The following does just that, but does not actually scale the image:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Img(QWidget):
def __init__(self, parent=None):
super(Img, self).__init__(parent)
self.setAttribute(Qt.WA_StyledBackground, True)
self.setStyleSheet('background-color: orange')
window = QDesktopWidget().screenGeometry(0)
height = window.height()
layout = QVBoxLayout(self)
pixmap = QPixmap("test.png")
pixmap = pixmap.scaledToHeight(height)
label = QLabel()
label.setPixmap(pixmap)
label.setScaledContents(True)
layout.addWidget(label)
print(height)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
img = Img()
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(img)
layout.setAlignment(Qt.AlignCenter)
content = QWidget()
content.setLayout(layout)
w,h = (1024,670)
self.resize(w,h)
self.setCentralWidget(content)
self.show()
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
app.exec_()
Although it prints out height is 1050, what I see is a huge image and the window expands down past my monitor. Can someone explain the issue and what needs to happen for scaledToHeight()?
Here is an example of what I see:
And here is the actual image:
The image gets cut off because it gets extended past the monitor screen, and is also stretched oddly.

Related

Set dimensions of an SVG image in fullscreen using QSvgWidget in PyQT?

I am lost with my PyQT programm. I want to display SVG image on full screen, but I need to be able to set the scale and position of the image and rest of the screen fill with black colour.
I use QSvgWidget and regular QWidget on top of each other, but It is not a good solution, because it runs as two processes and two separate windows.
Could you tell me how to make this with only one widget
import sys, os
from PyQt4 import QtGui, QtSvg
class Display(QtSvg.QSvgWidget):
def __init__(self, parent=None):
super(Display, self).__init__(parent)
def main():
app = QtGui.QApplication(sys.argv)
black = QtGui.QWidget() #setting background with widget
black.showFullScreen()
form = Display()
form.setWindowTitle("Display SVG Layer")
form.showFullScreen()
form.setStyleSheet("background-color:black;")
form.load("E:\example.svg")
form.move(100,0)
form.resize(1900,1000)
app.exec_()
if __name__ == '__main__':
main()
perhaps You can use QGraphicsView and QGraphicsScene:
class MyGraphicsView(QGraphicsView):
def __init__(self, w, h, parent=None):
QGraphicsView.__init__(self, parent)
self.setGeometry(0, 0, w, h) # screen size
class MyGraphicsScene(QGraphicsScene):
def __init__(self, w, h, parent = None):
QGraphicsScene.__init__(self,parent)
self.setSceneRect(0, 0, w, h) # screen size
self.backgroundPen = QPen(QColor(Qt.black))
self.backgroundBrush = QBrush(QColor(Qt.black))
self.textPen = QPen(QColor(Qt.lightGray))
self.textPen.setWidth(1)
self.textBrush = QBrush(QColor(Qt.lightGray))
self.textFont = QFont("Helvetica", 14, )
# paint the background
self.addRect(0,0,self.width(), self.height(), self.backgroundPen, self.backgroundBrush)
# paint the svg-title
self.svgTitle = self.addSimpleText('Display SVG Layer', self.textFont)
self.svgTitle.setPen(self.textPen)
self.svgTitle.setBrush(self.textBrush)
self.svgTitle.setPos(200,75)
# paint the svg
self.svgItem = QGraphicsSvgItem('./example.svg')
'''
edit:
if necessary, get the size of the svgItem to calculate
scale factor and position
'''
self.svgSize = self.svgItem.renderer().defaultSize()
self.svgItem.setScale(0.25) # scale the svg to an appropriate size
self.addItem(self.svgItem)
self.svgItem.setPos(200, 125)
if __name__ == '__main__':
app = QApplication(sys.argv)
screen_size = app.primaryScreen().size()
width = screen_size.width()
height = screen_size.height()
graphicsScene = MyGraphicsScene(width, height)
graphicsView = MyGraphicsView(width, height)
graphicsView.setScene(graphicsScene)
graphicsView.show()
app.exec_()

How to make one tab bar in QTabWidget expendable?

I need to customize my QTabWidget so that one of its tab bars (lets say there are 4 tabs overall) has expanding property and will fill the remaining space between other tabs. Any ideas?
you can subclass QTabBar, set it to the width of your tabwidget (the height depends on the fontsize) and overwrite tabSizeHint():
class tabBar(QTabBar):
def __init__(self, width, height, parent=None):
QTabBar.__init__(self, parent)
self.setFixedSize(width, height)
def tabSizeHint(self, i):
f = 3 # Tab3 shall be f times wider then the other tabs
tw = int(self.width()/(self.count() + f -1)) # width per Tab
if i == 2: # Tab3
# return QSize(tw*f, self.height()) edited -> rounding error possible
return QSize(self.width() - (self.count() - 1)*tw, self.height())
return QSize(tw, self.height()) # all other tabs
and set this tabBar to your tabwidget:
tb = tabBar(tabWidget.width(), 34) # tabBars height depends on fontSize
tabwidget..setTabBar(tb)
looks like this:
edit:
if the tabWidget is resized, a resizeEvent() occurs. In this moment the tabWidget already has its new size and is repainted immediatedly after the resizeEvent(),
see QT-Doc QTabWidget.resizeEvent
So if the width() of the tabBar is adapted in resizeEvent(), the tabBar will always have the same width as the tabwidget. Because the tabSizeHint() depends on the width, all tabs will have the correct width too. So You can subclass QTabWidget() and overwrite resizeEvent() for a dynamical solution:
class tabWidget(QTabWidget):
def __init__(self, parent=None):
QTabWidget.__init__(self, parent)
def resizeEvent(self, event):
self.tabBar().setFixedWidth(self.width())
QTabWidget.resizeEvent(self, event)
To do this correctly, it's necessary to work backwards from the existing sizes of the tabs. This is because the tab sizes are affected by the current style, and by other features such as tab close buttons. It's also important to set a minimum size for the tab which is exandable (otherwise it could be resized to nothing).
Here is a simple demo that does all that:
from PyQt4 import QtCore, QtGui
class TabBar(QtGui.QTabBar):
def __init__(self, expanded=-1, parent=None):
super(TabBar, self).__init__(parent)
self._expanded = expanded
def tabSizeHint(self, index):
size = super(TabBar, self).tabSizeHint(index)
if index == self._expanded:
offset = self.width()
for index in range(self.count()):
offset -= super(TabBar, self).tabSizeHint(index).width()
size.setWidth(max(size.width(), size.width() + offset))
return size
class TabWidget(QtGui.QTabWidget):
def __init__(self, expanded=-1, parent=None):
super(TabWidget, self).__init__(parent)
self.setTabBar(TabBar(expanded, self))
def resizeEvent(self, event):
self.tabBar().setMinimumWidth(self.width())
super(TabWidget, self).resizeEvent(event)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.tabs = TabWidget(2, self)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.tabs)
for text in 'One Two Three Four'.split():
self.tabs.addTab(QtGui.QWidget(self), text)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 400, 200)
window.show()
sys.exit(app.exec_())

PyQt4 Mdi sub window not resizing properly

In the following example, when you click the button, the entire form is rebuilt adding a new label each time. At the end is a resize call that doesn't appear to work. While debugging, I validated the sizeHint() is returning the correct dimensions, and internally the widget thinks it is the correct size, but what is drawn is not correct. What can I do to force the MDI window to resize correctly? Also of note, when not sized correctly, if you manually start resizing, it suddenly snaps to the appropriate size.
import sys
import os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.Qt
class MdiWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.buildWindow()
def buildWindow(self):
main = QVBoxLayout()
button = QPushButton('Change Count')
button.clicked.connect(self.changeCount)
main.addWidget(button)
for i in range(self.count):
main.addWidget(QLabel(str(i)))
widget = QWidget()
widget.setLayout(main)
self.setCentralWidget(widget)
self.resize(main.sizeHint())
def changeCount(self, event):
self.count += 1
self.buildWindow()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Resize Test')
self.mdiArea = QMdiArea()
self.setCentralWidget(self.mdiArea)
child = MdiWindow()
self.mdiArea.addSubWindow(child)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())

How do I auto fit a Matplotlib figure inside a PySide QFrame?

I'm creating a simple PySide application that also uses MatPlotLib. However, when I add the figure into a QFrame, the figure doesn't automatically fit to the frame:
My graph is created using the following code:
class GraphView(gui.QWidget):
def __init__(self, name, title, graphTitle, parent = None):
super(GraphView, self).__init__(parent)
self.name = name
self.graphTitle = graphTitle
self.dpi = 100
self.fig = Figure((5.0, 3.0), dpi = self.dpi, facecolor = (1,1,1), edgecolor = (0,0,0))
self.axes = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.Title = gui.QLabel(self)
self.Title.setText(title)
self.layout = gui.QVBoxLayout()
self.layout.addStretch(1)
self.layout.addWidget(self.Title)
self.layout.addWidget(self.canvas)
self.setLayout(self.layout)
def UpdateGraph(self, data, title = None):
self.axes.clear()
self.axes.plot(data)
if title != None:
self.axes.set_title(title)
self.canvas.draw()
And it's added to the main Widget like so:
# Create individual Widget/Frame (fftFrame)
fftFrame = gui.QFrame(self)
fftFrame.setFrameShape(gui.QFrame.StyledPanel)
self.FFTGraph = GraphView('fftFrame', 'FFT Transform:', 'FFT Transform of Signal', fftFrame)
Here's a working code sample that shows you how to get it working. I first thought it was because of the stretch you added to the layout, which will use up the additional space around the other widgets. But when I removed it, it still wouldn't resize. The 'easy' solution is to add a resizeEvent, which lets you define the size of your GraphView widget. In this case I just set its geometry to be that of the QFrame, though you might want to add some padding and make sure you set a sensible minimum size for the QFrame.
from PySide import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.fft_frame = FftFrame(self)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.fft_frame)
self.setLayout(self.layout)
self.setCentralWidget(self.fft_frame)
class FftFrame(QtGui.QFrame):
def __init__(self, parent=None):
super(FftFrame, self).__init__(parent)
self.setFrameShape(QtGui.QFrame.StyledPanel)
self.parent = parent
self.graph_view = GraphView('fftFrame', 'FFT Transform:', 'FFT Transform of Signal', self)
def resizeEvent(self, event):
self.graph_view.setGeometry(self.rect())
class GraphView(QtGui.QWidget):
def __init__(self, name, title, graph_title, parent = None):
super(GraphView, self).__init__(parent)
self.name = name
self.graph_title = graph_title
self.dpi = 100
self.fig = Figure((5.0, 3.0), dpi = self.dpi, facecolor = (1,1,1), edgecolor = (0,0,0))
self.axes = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self)
self.Title = QtGui.QLabel(self)
self.Title.setText(title)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.Title)
self.layout.addWidget(self.canvas)
self.layout.setStretchFactor(self.canvas, 1)
self.setLayout(self.layout)
self.canvas.show()
def update_graph(self, data, title = None):
self.axes.clear()
self.axes.plot(data)
if title != None:
self.axes.set_title(title)
self.canvas.draw()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

Pyqt: How-to set item always in the center of a QGraphicsView when scrolling is possible?

I have a QGraphicsView. To that I added a QGraphicsScene and to that a added an QPixmap(*.jpeg) and QGraphicsEllipseItem(a circle). The QPixmap is much more bigger than the QGraphicsView, so scrolling is enabled. The problem is that both QPixmap and QGraphicsEllipseItem are moving. But I want a fixed position for the QGraphicsEllipseItem in QGraphicsView. It should always be in the center of the QGraphicsView.
How can I do that? Hope someone can help.
Add a signal handler for the scroll signal of the scroll bars (use QAbstractSlider::sliderMoved()).
Then you can query the view for it's left/top offset and size and position the circle accordingly. See the explanation for QAbstractScrollArea to get you started.
If you subclass QGraphicsView, you can override the scrollContentsBy method to set the position of the ellipse whenever the scroll area changes. Here's some really minimal code:
import sys
from PyQt4 import QtGui
class MyView(QtGui.QGraphicsView):
def __init__(self, scene, parent = None):
super(MyView, self).__init__(parent)
self.scene = scene
self.setScene(scene)
self.ellipse = QtGui.QGraphicsEllipseItem(0, 0, 30, 30, scene = self.scene)
self.scene.addItem(self.ellipse)
def scrollContentsBy(self, x, y):
super(MyView, self).scrollContentsBy(x, y)
self.ellipse.setPos(self.mapToScene(28, 28))
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
pixmap = QtGui.QPixmap()
pixmap.load('imagefile.jpg')
scene = QtGui.QGraphicsScene(self)
scene.setSceneRect(0, 0, pixmap.width(), pixmap.height())
item = QtGui.QGraphicsPixmapItem(pixmap)
scene.addItem(item)
self.view = MyView(scene, self)
self.view.setMinimumSize(100, 100)
def main():
app = QtGui.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
app.exec_()
if __name__ == '__main__':
main()

Resources