Showing posts with label script. Show all posts
Showing posts with label script. Show all posts

Tuesday, 11 March 2014

Excellent QT Drag and Drop Tutorial

This link is what got me started in understanding how QT works with drag and drop. I will post a link to the file in my github account that will use the results of this tutorial (although it is subject to change over time), but with code samples in-page.

http://rowinggolfer.blogspot.ca/2010/04/pyqt4-modelview-drag-drop-example.html

Here is my github source file with drag and drop classes in them:
https://github.com/NucleaPeon/QTCIDE/blob/master/src/view/main/widget.py

Note the following sections:

class Droppable(QtGui.QLabel):
    
    def __init__(self):
        super(Droppable, self).__init__()
        self.mime = QtCore.QMimeData()
        # ... more

    def mousePressEvent(self, event):
        mime = QtCore.QMimeData()
        mime.setText(self.mime.text())
        hotSpot = event.pos()
        mime.setData("application/x-hotspot", str(hotSpot.x()))
        
        # Create a pixmap of size of self
        pixmap = QtGui.QPixmap(self.size())
        self.render(pixmap)
        drag = QtGui.QDrag(self)
        drag.setMimeData(mime)
        drag.setPixmap(pixmap)
        drag.setHotSpot(hotSpot)
        
        dropAction = drag.exec_(QtCore.Qt.CopyAction|QtCore.Qt.MoveAction, QtCore.Qt.CopyAction)
Important things to note is that droppable object is a QtGui object, therefore has a visual place in the UI, has methods such as mousePressEvent in them.

Another odd thing you may notice, is that __init__ has a variable named self.mime, whereas mousePressEvent has just mime. Through trial and error, I found that the mousePressEvent method requires an instantiation *each* time the mouse is pressed, otherwise it fails to work. I set a variable in __init__ so that I only have one copy of the data and don't need to keep setting it (hardcoding == bad) in the method itself; changing the constructor variable will change the behaviour of the entire class easily.

class DropCanvas(QtGui.QGraphicsView):
    
    def __init__(self):
        super(DropCanvas, self).__init__()
        self.setAcceptDrops(True)
        self.scene = model.scene.ProjectScene()
        
    def dropEvent(self, event):
        # Here is where you put actions you want when the drop is done
        
        
    def dragEnterEvent(self, event):
        event.accept()

This class is the QtGui droppable object. I have it set to QGraphicsView, but it can be anything, such as a different view or a dock or panel, provided it inherits QWidget (I think).

Personally, I have an object that is set up specifically upon a drop event. The code here won't work with a QGraphicsView, but it used to be a QListView so it did work.

class CanvasItem(QtGui.QStandardItem):
    
    def __init__(self, *args, **kwargs):
        super(CanvasItem, self).__init__(*args)
        self.setEditable(False)


The item inherits a standard item and disables editing of itself.


Put all of the classes together and you can drag and drop!

Tuesday, 9 July 2013

Speedway Revolution 420 RFID Tag Reader in Python

So I recently was working on connecting a piece of software to a reader via a socket.

The vendors had a great script for connecting to it via ruby, as shown in the code below:

require 'socket'

s = TCPSocket.new '192.168.2.165', 14150

while line = s.gets
    puts line.chop
end

s.close


This code is available, you can see it here in the video:
http://learn.impinj.com/articles/en_US/RFID/Reading-Tags-over-TCP-IP-Socket-Using-Speedway-Connect-Software/

The site presents .NET code for connecting as well. However, as I do most of my work in python, I figured I'd keep things simple and convert their script to it.

---

The reason I'm writing this post is because I had one hell of a time getting to the point where it *would* read, because it would keep failing on the connect() method and from then on, I would have a Connection Refused error whenever I ran the python OR the ruby script. If you are having troubles with the Speedway Revolution 420 reader, know this:

* If you get Connection Refused errors, you need to browse to the ReaderConnect software, found at the reader ip address on port 8080. Click the save button, even if you haven't made any changes. This will allow connections to be received again, as I imagine it closes whatever broken connection python has left behind.
* You must use python 2.7 (or 2.x series, though I haven't tested beyond that) in order for it to run. When my code was failing, the header was "#!/usr/bin/env python", which on my linux mint system, would default to python 3. It was only until I *explicitly* stated "#!/usr/bin/env python2.7" that it miraculously worked. Here is the code:

#!/usr/bin/env python2.7

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.2.165", 14150))

data = s.recv(1024)
data = data.strip('\n')
while 1:
    print data
    data = s.recv(1024)
    data = data.strip('\n')
    
s.shutdown(socket.SHUT_RD)
s.close()


It makes two assumptions:

1. You want to read 1024 bytes. 0 does NOT work, it leaves me with an empty screen because the data variable does not get assigned to anything more than an empty string.
2. If you set the output to Linefeed, or Carriage Return Linefeed, this script will work. If you don't set the line ending value in the Output tab, there could be some issues.

Hopefully this script can help someone, someday.