Posts about pyqt (old posts, page 5)

2010-09-09 13:50

Making deployment of desktop Python apps trivial: an idea

Proprietor and printer in front of Schwartz Print Shop in Minneapolis

Here's what I'm thinking: how hard could it be to make PyQt app deployment absolutely easy? Well, I am guessing: not very hard.

Here's the trick: see what works in the real world, and adopt it.

Question: what has deployed billions of apps and has its users happy? Answer: phones app stores.

Question: how do they work? Answer: well, that's not that short, so let's start explaining.

As I see it, a reasonable app store has the following components:

A Stable Deployment Target

You can't deploy from the store if you don't know what you are deploying into. If the target platform is shaky, you just can't know how to deploy without user assistance, and we are trying to make this easy for the user, which means that's not acceptable.

So, what's a stable deployment target we can provide?

  • PyQt (so we can deploy GUIs to all major desktop platforms)
  • Python standard library
  • Selected modules

What can be (and should be) bundled with the app?

  • Pure python modules
  • Artwork and other resources

What may be bundled:

  • Python modules written in C/C++, but you then have to redo the app for each platform, and that kinda sucks.

Deployment Services

  • Apps should be able to check if there is a new version of them in the store, to ask for upgrades.
  • Apps should be added by the deployment platform nicely into the host system's menus, desktop, etc.

Monetization Services

  • Some way to charge for apps. Even for open source apps, you could ask for U$S0.99 if you install them through the store. Optional, of course, and up to the app owner.
  • Ad platform? There must be a good one for desktop apps somewhere?

The Store Itself

  • A website that downloads a "package" associated with a local deployment application.
  • A app store app. Install things not via web, but via a desktop application.

I don't expect a functional version of this would take me more than a week working fulltime to implement. Of course then there are all sorts of usability, looks, etc. things to consider.

And... I am going to do something I very rarely do. I am going to ask for money.

As an experiment, I have setup a project at http://www.indiegogo.com/Qt-Shop and set a funding goal of U$S 600.

There you can fund me. I promise that if the project is totally funded, I will deliver. If it isn't, I may deliver anyway. I would prefer to have the money though.

The platform would be released under GPLv2 or later.

2010-07-24 20:37

This is why Qt (and PyQt) are cool

Alejandro Dolina once wrote (and this is from memory that's probably 25 years old) of a round table discussing "What's Tango?", and how after two hours of discussing the nature, characteristics and history of tango, one of the members of the panel picked up a bandoneón, played "El apache argentino" stood up and left without saying a word.

So, why are Qt and PyQt cool?

Audio player widget:

# -*- coding: utf-8 -*-

import sys, os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.phonon import Phonon
import icons_rc

class AudioPlayer(QtGui.QWidget):
    def __init__(self, url, parent = None):

        self.url = url

        QtGui.QWidget.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Preferred)


        self.player = Phonon.createPlayer(Phonon.MusicCategory,
            Phonon.MediaSource(url))
        self.player.setTickInterval(100)
        self.player.tick.connect(self.tock)

        self.play_pause = QtGui.QPushButton(self)
        self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))
        self.play_pause.clicked.connect(self.playClicked)
        self.player.stateChanged.connect(self.stateChanged)

        self.slider = Phonon.SeekSlider(self.player , self)

        self.status = QtGui.QLabel(self)
        self.status.setAlignment(QtCore.Qt.AlignRight |
            QtCore.Qt.AlignVCenter)

        self.download = QtGui.QPushButton("Download", self)
        self.download.clicked.connect(self.fetch)

        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.play_pause)
        layout.addWidget(self.slider)
        layout.addWidget(self.status)
        layout.addWidget(self.download)

    def playClicked(self):
        if self.player.state() == Phonon.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def stateChanged(self, new, old):
        if new == Phonon.PlayingState:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_pause.svg'))
        else:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))

    def tock(self, time):
        time = time/1000
        h = time/3600
        m = (time-3600*h) / 60
        s = (time-3600*h-m*60)
        self.status.setText('%02d:%02d:%02d'%(h,m,s))

    def fetch(self):
        print 'Should download %s'%self.url

def main():
    app = QtGui.QApplication(sys.argv)
    window=AudioPlayer(sys.argv[1])
    window.show()
    # It's exec_ because exec is a reserved word in Python
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Video player widget:

import sys, os
from PyQt4 import QtCore, QtGui, uic
from PyQt4.phonon import Phonon
import icons_rc

class VideoPlayer(QtGui.QWidget):
    def __init__(self, url, parent = None):

        self.url = url

        QtGui.QWidget.__init__(self, parent)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Preferred)


        self.player = Phonon.VideoPlayer(Phonon.VideoCategory,self)
        self.player.load(Phonon.MediaSource(self.url))
        self.player.mediaObject().setTickInterval(100)
        self.player.mediaObject().tick.connect(self.tock)

        self.play_pause = QtGui.QPushButton(self)
        self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))
        self.play_pause.clicked.connect(self.playClicked)
        self.player.mediaObject().stateChanged.connect(self.stateChanged)

        self.slider = Phonon.SeekSlider(self.player.mediaObject() , self)

        self.status = QtGui.QLabel(self)
        self.status.setAlignment(QtCore.Qt.AlignRight |
            QtCore.Qt.AlignVCenter)

        self.download = QtGui.QPushButton("Download", self)
        self.download.clicked.connect(self.fetch)
        topLayout = QtGui.QVBoxLayout(self)
        topLayout.addWidget(self.player)
        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.play_pause)
        layout.addWidget(self.slider)
        layout.addWidget(self.status)
        layout.addWidget(self.download)
        topLayout.addLayout(layout)
        self.setLayout(topLayout)

    def playClicked(self):
        if self.player.mediaObject().state() == Phonon.PlayingState:
            self.player.pause()
        else:
            self.player.play()

    def stateChanged(self, new, old):
        if new == Phonon.PlayingState:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_pause.svg'))
        else:
            self.play_pause.setIcon(QtGui.QIcon(':/icons/player_play.svg'))

    def tock(self, time):
        time = time/1000
        h = time/3600
        m = (time-3600*h) / 60
        s = (time-3600*h-m*60)
        self.status.setText('%02d:%02d:%02d'%(h,m,s))

    def fetch(self):
        print 'Should download %s'%self.url

def main():
    app = QtGui.QApplication(sys.argv)
    window=VideoPlayer(sys.argv[1])
    window.show()
    # It's exec_ because exec is a reserved word in Python
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

...

2010-07-23 02:50

Desktop apps and clouds (with video)

I enjoy creating desktop applications. That means I may be a member of a dying breed, since web apps are going to make us all obsolete next week, but I do enjoy doing it.

The bad side of it is, of course that sometimes it's much more convenient to use a web application. For example, I have abandoned my own baby (uRSSus) because google reader is just easier and more convenient to use.

But then I thought... what bothers me of uRSSus? And there are quite a few things!

  1. It's not in all computers I may use

    That means I will not ever be able to use it exclusively.

  2. It's pretty useless without an Internet connection (but so is google reader mostly)

  3. Since I can't use it exclusively, I end with feeds on uRSSus that are not on google reader and viceversa.

  4. It's freaking slow

So, I decided to see what I could do about that without giving up the good side of uRSSus:

  1. It looks much nicer than a web app, because it looks like a desktop app
  2. It does things like opening the site instead of showing the feed item (great for partial content feeds)
  3. I wrote it (yes, that's a feature for me. I like self-made programs)

So, this attempt at rewriting the desktop RSS reader produced this:

As you can see in the above video, this reader syncs the subscription list to google reader. It will also eventually sync your read/unread posts.

It still can open full sites instead of feed items, it has/will have a heck of an offline mode (full pages captured as images, for example), and... it's very very fast.

It's much faster than google reader in Chromium, and hella faster than uRSSus. That was done via smarter coding, so it probably means I was braindead before and experienced a minor recovery.

The code is not fit for release (for example, the database schema will change) but you can try it: http://code.google.com/p/kakawana/source/checkout

2010-07-17 03:53

Slow-Slow and Fast-Fast (video)

My previous post explained how to cache whole web pages as images. Now see it in action. This is a lightweight RSS reader, optimized for comic books (but it works for any feed) and for offline use (but it works online too, of course).

Not ready for public use yet, but if you look around you can find the code somewhere ;-)

2010-05-12 20:08

What's wrong with this dialog?

I am writing a book. And I am writing a chapter about UI design. And why not use the Internet?

So, go ahead and tell me all that's wrong with this dialog!

radio-14

For example, I don't like the dead space at the bottom-left, the different-size of the "Close" button, and the misalignment of the icons.

Are those valid concerns? Are there many more? Would you do it completely different?

The book is open source, and available at http://nomuerde.netmanagers.com.ar (In spanish, sorry!)

2010-04-11 05:12

I am posting very little because I am writing a lot.

I am just not writing here. I am writing a book instead.

What book am I writing? A book about python programming, of course! It's called "Python No Muerde" (Python Doesn't Bite) and it's in spanish.

Now, I am the first to admin: I am not a great programmer. And I am not a great writer. But I have lots of things to say. If I can organize them correctly, they even make sense sometimes!

So, I am giving this write-long-stuff thing a try.

Of course since I am an open source nerd, I can't do things the usual way, therefore, the book is under Creative Commons. And because I am a programmer, I hacked together a (if I may say so myself) decent structure to handle book-writing.

  1. I write in restructured text
  2. I use rst2pdf to create PDFs both of individual chapters and the whole thing.
  3. I use rest2web to create a website
  4. I use mercurial (at googlecode) to handle revision control and history.
  5. I use make to control rebuilding of chapters when code changes, or images get updated, etc.

Of course it's more complicated than that, the PDFs are in the site, the site is uploaded via rsync, the uploads and rebuilds are triggered by hg push, and so on.

In any case, I may post a few times about how this whole thing works, here is the output of the machinery:

http://nomuerde.netmanagers.com.ar

2010-03-03 19:28

Hacked on kuatia for a couple of hours...

As mentioned previously, I am hacking a bit on a proof-of-concept word processor. Right now, it's hosted on googlecode and called kuatia.

Now, it is far from being useful for anything, but... it can do nested itemized and bulleted lists.

Here's a screenie of the editor and the PDF output it produces via reStructured Text:

editando2

Personally I think that's not too bad.

2010-02-25 11:16

Marave 0.7 released

I just uploaded version 0.7 of Marave, my fullscreen text editor to http://marave.googlecode.com

Marave is a "relaxing" text editor inspired by ommwriter, DarkRoom and many others. It combines a spartan fullscreen UI with a vanishing UI, which gets out of the way of your text.

It supports syntax highlighting, inine spellchecking, background music, audible keyboard feedback, themes, is extensible via plugins, and much more.

Here's a screenshot:

marave18

There are no major new features in 0.7, but there are important internal changes and some major bugs fixed:

  • Fixed bug that broke opening files if you had no spellchecker
  • Implemented basic RTL language support
  • Several other minor fixes
  • Refactored the editor component so it can be reused

2010-02-24 14:13

A teaser for an idea

I have been thinking on what I really really want in a word processor. And then what would it take to create such a thing.

A few minutes of playing have led me the way of this teaser (video here if you can't see it):

Could something come out of it? Who knows.

2010-02-23 14:23

Editor: a better QTextEdit

Writing an editor is reinventing the wheel. I know that. I tell myself Marave is a fine wheel, with distinct features, and I think that is true, but, if you are reinventing the wheel, there's no need to reinvent the axle and the spoke, too.

So, I refactored the stuff that I think a text editor must provide into a nice library, so the next time someone must invent a wheel, he can use Marave's neat spokes and axles:

So, introducing Editor, the most-obviously named class ever! It's a text editing widget for PyQt with extra features, which you can use as a drop-in replacement for a QTextEdit or QPlainTextEdit.

Right now, it lives inside Marave's SVN but it may even move out someday.

Here are its features:

  • Syntax highlighting

    And I don't mean "in theory", like QTextEdit and company do! Editor can highlight a bunch of languages, because it uses GNU source highlight via Lorenzo Bettini's Source Highlight Qt.

  • Spell checking

    If you have PyEnchant installed and the right dictionaries, it will do online spellchecking.

  • Search and Search+Replace widgets

    The Editor class can give you nice widgets for search or search and replace already hooked with the editor widget, so you can add them to your app's UI easily.

  • new/open/save/saveas methods:

    Don't implement opening/saving, etc yourself! That's always the same code!

Hopefully this will be helpful for someone else :-)

Contents © 2000-2019 Roberto Alsina