3

I'm writing a program that will allow me to upload photos to TUMBLR via their API, I've got the uploading working (thanks to you guys).

I've put a 'queueBox' on the side of the GUI, which displays the image names, and they are stored in a QListWidget. I've put this in my Main Class' constructor:

def __init__(self):
    QtGui.QMainWindow.__init__(self)
    self.setupUi(self)
    self.queueBox.itemClicked.connect(self.displayPhoto)

and I have this method:

def displayPhoto(self, item):
    tempName = (item.text())
    print tempName
    self.myLabel.setPixmap(QtGui.QPixmap(_fromUtf8(directory + '\\' + tempName)))  
    ## self.myLabel.pixmap(QPixmap.scaled(aspectRatioMode = Qt.IgnoreAspectRatio))
    ## ^ ^ ^ What do I do with this? How do I set it to maintain aspect ratio?
    ## Currently it says ''NameError: global name 'Qt' is not defined''

This sucessfully draws the image on to myLabel which is a QLabel, however, It is very scaled, I have

self.myLabel.setScaledContents(True)

in my ui_mainWindow class, and if I turn it to False, it fixes the scaling but it only shows a small portion of the image because the image is much larger than the QLabel. What I want is to be able to maintain the aspect ratio, so it doesn't look scaled and horrible.

I found this: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qpixmap.html and it says how to use it, however I can't get it to work as shown in the code above in my comments. Does anyone know how to use this? If so, can you provide me with an example, I've tried searching but most of the results I get are working examples in C++, not python.

Thanks!

aaron
  • 39,695
  • 6
  • 46
  • 102
Anteara
  • 729
  • 3
  • 14
  • 33

2 Answers2

13

Get rid of the

self.myLabel.setScaledContents(True)

call (or set it to False). It is filling your widget with the pixmap without caring about the aspect ratio.

If you need to resize a QPixmap, as you have found, scaled is the required method. But you are invoking it wrong. Let's look at the definition:

QPixmap QPixmap.scaled (self, 
                        int width, 
                        int height, 
                        Qt.AspectRatioMode aspectRatioMode = Qt.IgnoreAspectRatio,
                        Qt.TransformationMode transformMode = Qt.FastTransformation)

Return type of this function is QPixmap, so it returns a scaled copy of the original pixmap.

Then you need a width and a height, describing the (maximum) final size of the pixmap.

Two more optional parameters. aspectRatioMode deals with the, well aspect ratio. The documentation details the different options and their effects. transformMode defines how (which algorithm) the scaling is done. It might change the final quality of your image. You probably don't need this one.

So, putting it together you should have (Qt namespace is inside QtCore):

# substitute the width and height to desired values
self.myLabel.setPixmap(QtGui.QPixmap(_fromUtf8(directory + '\\' + tempName)).scaled(width, height, QtCore.Qt.KeepAspectRatio))

Alternatively, if you have a fixed size QLabel, you could call the .size() method to get the size from it:

self.myLabel.setPixmap(QtGui.QPixmap(_fromUtf8(directory + '\\' + tempName)).scaled(self.myLabel.size(), QtCore.Qt.KeepAspectRatio))

Note: You might want to use os.path.join(directory, tempName) for the directory + '\\' + tempName part.

Avaris
  • 35,883
  • 7
  • 81
  • 72
  • 1
    Alright, thank you so much, that works great. I modified it a little : `self.myLabel.setPixmap(QtGui.QPixmap(_fromUtf8(directory + '\\' + tempName)).scaled(self.myLabel.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))` I added "smoothTransformation" as it makes the quality much better when it fits the image to the label. However, when the image is created, it is situated on the left of the label, i.e. if it's a square, it wont be in the middle of the label, it will be at the left, I searched the documentation and couldn't find anything to perform what I'm after, any ideas? – Anteara Feb 20 '12 at 05:24
  • Oh, i wasn't very informative in the above. What i want to do is have a square image situated in the middle of the label, as opposed to the left, so it looks proportional to the rest of the window. I'll show you an example of what I mean: http://i.imgur.com/0nQWU.jpg As you can see the Square images are positioned on the left as opposed to the middle yet widescreen images are fine. – Anteara Feb 20 '12 at 05:33
  • @Anteara: That is up to the `QLabel`. Just set the alignment for it either by Designer (if you designed the UI by Designer) or by calling `self.myLabel.setAlignment(QtCore.Qt.AlignCenter)`. – Avaris Feb 20 '12 at 06:52
  • Alright, i've run across one more problem if you're willing to help; that is, masking text so it doesn't display when you enter your password. i HAVE been able to do this, by reading the documentation, via this: `self.passWord.setEchoMode(QtGui.QLineEdit.Password)` This makes the input what you normally see in a password field, however, to my surprise, this ALSO makes the OUTPUT the common seen circles, as shown by this: `password = smart_str(self.passWord.displayText()) print password` – Anteara Feb 20 '12 at 09:56
  • Please note that I need to put it as smart_str as opposed to str because I get a UnicodeEncodeError if I don't. `from django.utils.encoding import smart_str, smart_unicode` If I type a 3 letter password, this is the output `●●●`. The output should read "asd" (that was the input) because I can't validate ●●● to authenticate for obvious reasons. – Anteara Feb 20 '12 at 09:58
  • oh, nevermind, I got it working, to anyone reading this, .displayText() appears to display the masked text. I used .text() to display the input while the QLineEdit still displays the masked input text. – Anteara Feb 20 '12 at 10:10
1

PyQt5 code change update:

The above answer of avaris needed a PyQt5 update because it breaks.

QPixmap.scaled (self, int width, int height, Qt.AspectRatioMode aspectRatioMode = Qt.IgnoreAspectRatio

Keeping the self in the code results in below traceback error.

TypeError: arguments did not match any overloaded call: scaled(self, int, int, aspectRatioMode: Qt.AspectRatioMode = Qt.IgnoreAspectRatio, transformMode: Qt.TransformationMode = Qt.FastTransformation): argument 1 has unexpected type 'MainUI' scaled(self, QSize, aspectRatioMode: Qt.AspectRatioMode = Qt.IgnoreAspectRatio, transformMode: Qt.TransformationMode = Qt.FastTransformation): argument 1 has unexpected type 'MainUI'

Thus this should be (without "self", "Qt") as stated below:

QPixmap.scaled (int width, int height, aspectRatioMode = IgnoreAspectRatio

or:

QPixmap.scaled (int width, int height, aspectRatioMode = 0)

KeepAspectRatio = 2... but used as provided by aspectRatioMode = 2 in above code. Enjoy!

ZF007
  • 3,708
  • 8
  • 29
  • 48
  • What is `aspectRatioMode = 0` or `aspectRatioMode = 4`?, you should use an enum element name rather than the assumed value. [I don't see one corresponding to value 4](https://doc-snapshots.qt.io/qt5-5.15/qt.html#AspectRatioMode-enum). – mins May 12 '21 at 11:59
  • @mins Thanks for the attention on the value. Typo I guess. – ZF007 May 29 '21 at 08:23