I don't think there is anything wrong with the approach you are taking. This is the norm. The framework can't provide every type of functionality, but they do give you a ton of building blocks to make it easy to compose your own.
There isn't much to say about your code other than me nit picking a little :-)
But here are some small things...
def mousePressEvent(self, *args, **kwargs):
self.emit(QtCore.SIGNAL('clicked()'))
return QtGui.QFrame.mousePressEvent(self, *args, **kwargs)
An event method will only receive a single event argument, and you don't need to return anything. Right now this would be returning None all the time. You can just take the single event arg, and then call the superclass method with it.
Also, you might want to consider using the new-style signal-slots if you are just learning...
You can define signals as class attributes like this:
class TitleFrame(QtGui.QFrame):
clicked = QtCore.pyqtSignal()
... And then you can emit like this:
self.clicked.emit()
... And connections to the slot in your other class would be like:
self.titleFrame.clicked.connect(self.printSomething)
Its much cleaner and easier to use. And you can create signals with different signatures and slots of the same name that take different signatures.
Thats pretty much it. Like I said, the rest is just nit-picking (I find it more obscure to define your UI setup in a bunch of smaller methods that you call in a row, when they depend on each other, such as needing to connect the signal and knowing that the UI object is there).