Using Python to realize the QQ game everyone come to pick a tool _python

Source: Internet
Author: User
Tags abs numeric value first row python script

Long time no write technology related articles, this time write an interesting, about an interesting game--qq, about an interesting language--python, about an interesting library--QT.

This is a QQ for everyone to find fault (beauty finding fault) auxiliary plug-in, the development of the reason is to see Dad every day playing this game, scores are miserable negative 4,000 more. He played the game has his fun, not very concerned about winning and losing, I do this is also just self entertainment, by the way to ask him a good, after all, we do programming is really difficult to have the opportunity to show in front of the parents Lulu hand. Originally wanted to write a very simple things, but because of the process of Dad's many ridicule, forcing me to do my best to perfect, and finally formed a small product.

Touch Python is 2010, encounter, wrote a little gadget last year, leaving the former company with a Python+wxpython working tool, and quite popular. Change the company after hard study c++&qt, very regret chose Wxpython instead of PYQT, not in the same vein. The longer you use QT, the more you have to like it, and it's just the right thing to write.

Don't talk much, get to the point. This is not a complete code explanation, but some of the techniques in the process are shared, including some technical points that were later discarded. It was also very laborious to search for these things, and to make a note here, the latter may be able to search for the proceeds.
Let's go to the last picture:

Say this is the game of the most out of the mirror mm, and qq what relationship ah?
The auxiliary tool added two buttons in the game, click "Contrast" to find "stubble" automatically, use the Blue small box to mark, click "Erase" to clear the mark.

Game window probing
this has to use the PyWin32 library, it is on the Windows interface of the Python package, VC can do it basically all right.
Download Address: http://sourceforge.net/projects/pywin32/, but can not directly point download icon, or down is a Readme.txt, point "Browse all Files" to find the required version.

#coding =gbk  Import Win32gui
 
Game_hwnd = Win32gui. FindWindow ("#32770", "everyone to pick fault") print Game_hwnd


QQ Fault is a dialog box window, class is "#32770", such a window on the desktop there are many, so also with the title "Everyone to find fault" matching, and because it is Chinese, so the first line specifies the use of GBK encoding, or either cannot find, or run an error.

Game Picture Extraction
extraction of the image using a screenshot of the way, to find the window after the window mentioned the most before the window screen. The screenshot uses the famous Python Imaging library (PIL).

Import imagegrab Import Win32con
 
Win32gui. ShowWindow (Game_hwnd, Win32con.sw_restore) # Forced to display the interface after the screenshot Win32gui. SetForegroundWindow (Game_hwnd) # will be the game window mentioned in the front  # clipping to get the whole map game_rect = Win32gui. GetWindowRect (game_hwnd)
src_image = Imagegrab.grab ((game_rect[0) + 9, Game_rect[1] + 190, game_rect[2]-9, Game_rec T[1] + 190 + 450)) # src_image.show ()  # Cut the left and right content picture Left_box = (9, 0, 450)
Right_box = (517, 0, 517 + 500, 450 )
Image_left = Src_image.crop (left_box)
image_right = Src_image.crop (right_box) # image_left.show () # Image_ Right.show ()

The coordinates used above are simply filled in for the demo code, which actually uses variable parameters and distinguishes resolution or something.
PiL is a powerful Python graphics library (using documents), and will need to be used for comparative analysis. Imagegrab is a PIL module for image capture. Imagegrab.grab () with no parameters to screen, return an Image object, or use a tuple as a parameter to specify the range to intercept (the coordinates of the upper left and lower two points), both of which are not with the mouse pointer, There is also a imagegrab.grabclipboard () to collect images from the system Clipboard.
After getting image images, you can use the show () method, using the system default image viewing tool to open, easy to debug, or save (filename) as a file, corresponding to the Image.open (filename) open to get.

Grab got an Image object containing the left and right pictures, the crop (box) method can be used to crop the specified area, respectively, to get about two game pictures.

Compare to get two diagram contents different areas
It is natural to think of the two map cropped to n small pictures, respectively, the corresponding small picture is not equal to the "stubble" area, the only question is how to judge the content of two pictures inconsistent?

At first I thought it was going to be a little tricky until I found the Image.histogram () function, which is used to get the color histogram of the image. I also like photography, know that the histogram can represent a picture of a variety of brightness (or color) of the number, the histogram of the two natural pictures is basically different, unless the two image symmetry, color uniformity but the arrangement is different, but even so, the two graph continues to split, the histogram of its children will be different. The histogram is a kind of graph to the numerical transformation, compares the two graphs color numerical value to know whether has the difference.

An image in RBG color format, the histogram () function returns an array of length 768, 第0-255 represents a red 0-255, 第256-511 a 0-255 of the table color green, 0-255 of the table color blue, and a numeric value that represents the number of pixels for that color. Therefore, the sum of all members of the histogram () list equals the pixel value of the image change x 3.

Write a function to get the numerical difference of the two graph comparison:

 EF compare (Image_a, image_b): ' Returns the difference value of the two figure to return two figure red-green-blue difference is extremely much more than and ' Histogram_a = Image_a.histog Ram () Histogram_b = Image_b.histogram () If Len (histogram_a)!= 768 or Len (histogram_b)!= the None 768:return = 0 red_b = 0 for i in xrange (0, 256): Red_a + = histogram_a[i + 0] * I red_b + = histogram_b[i + 0] * I diff_red = 0 If red_a + red_b > 0:diff_red = ABS (red_a-red_b) * 10000/max (red_a, red_b) green_a = 0 Green_b = 0 for I I n xrange (0, 256): Green_a = histogram_a[i + 256] * I Green_b + + histogram_b[i + 256] * I diff_green = 0 if Gree N_a + green_b > 0:diff_green = ABS (green_a-green_b) * 10000/max (green_a, green_b) blue_a = 0 Blue_b = 0 fo R i in xrange (0, 256): Blue_a + + histogram_a[i + i] * I blue_b + + histogram_b[i +] * I diff_blue = 0 if bl Ue_a + blue_b > 0:diff_blue = ABS (blue_a-blue_b) * 10000/max (blue_a, Blue_b) return diff_red, Diff_green, dif F_blue 

Adds the red-green-blue difference value returned by the function, which indicates that the range is different if the predetermined threshold of 2000 is exceeded. This method of calculation is a bit "dirt", but the problem to be solved is very effective, there is no further improvement.

Cut the left and right large figures into smaller graphs and compare results = [0 for a-xrange (0)] for B-xrange (0)] for Col in xrange (0): For
  row in X Range (0):
    clip_box = (col *, Row *, (col + 1) *, (row + 1) *)
    Clip_image_left = Image_left.crop (cl Ip_box)
    clip_image_right = Image_right.crop (clip_box)
    Clip_diff = Self.compare (Clip_image_left, Clip_image_ right)
 
    if sum (clip_diff) >:
      result[row][col] = 1


A large image is a 500x450, separated into 10x10 small chunks, defines a 50x45 two-bit array storage results, respectively, the difference is greater than the threshold of the array region marked as 1.
Mark a game with a different area on both sides

Initially I used some of the PyWin32 functions, to get the game window handle directly on the above drawing, but I am not familiar with Windows programming, do not know how to solve the game itself after redrawing my mark erase the problem, and then moved to QT. Use QT to create a qwidget window that is as transparent as the size of the game, overlay the game window, and draw the tag with a mask. Mark data has been recorded in the result array, drawing a square at the specified position indicates that the area is different, to note that the boundary between the two squares do not draw, to avoid too much interference in the grid game. In addition to the tag, two buttons are drawn to trigger the contrast and erase.

EF paintevent (Self, event): # Reset Mask Image Self.pixmap.fill () # Create a drawing qpainter with a stroke thickness of 2 pixels # a blue background picture has been placed on the Qt form beforehand, so the mask pattern is dropped. Line is blue p = qpainter (Self.pixmap) P.setpen (Qpen (Qbrush (qcolor (0, 0, 0)), 2) for row in Xrange (Len (Self.result)): For CO L in Xrange (Len (self.result[0])): if Self.result[row][col]!= 0: # Set a base point to avoid arithmetic too ugly base_l_x = self. Anchor_left_x + self. Clip_width * Col base_r_x = self. Anchor_right_x + self. Clip_width * Col base_y = self. Anchor_y + self. Clip_height * row if row = = 0 or Self.result[row-1][col] = = 0: # If the first row, or the upper grid is empty, draw a top p.drawline (base_l_x, base_y, BA Se_l_x + self. Clip_width, base_y) p.drawline (base_r_x, base_y, base_r_x + self. Clip_width, base_y) if row = = Len (self.result)-1 or Self.result[row + 1][col] = 0: # If the last row, or the bottom of the grid is empty, draw a bottom p.drawline (base_l_x, base_y + self.) Clip_height, base_l_x + self. Clip_width, base_y + self. Clip_height) P.drawline (base_r_x, base_y + self. Clip_height, base_r_x + self. Clip_width, Base_y +Self. clip_height) If Col = = 0 or Self.result[row][col-1] = 0: # If it is the first column, or the left grid is empty, draw a left p.drawline (base_l_x, base_y, base_l_x , Base_y + self. Clip_height) P.drawline (base_r_x, base_y, base_r_x, base_y + self. clip_height) If col = = Len (self.result[0])-1 or Self.result[row][col + 1] = = 0: # If it is the first column, or the grid on the right is empty, draw a right p.drawline (base _l_x + self. Clip_width, base_y, base_l_x + self. Clip_width, base_y + self. Clip_height) P.drawline (base_r_x + self. Clip_width, base_y, base_r_x + self. Clip_width, base_y + self. Clip_height) # Draw the area of the button on the mask to avoid the button being masked P.fillrect (Self.btn_compare.geometry (), Qbrush (qcolor (0, 0, 0)) P.fillrect ( Self.btn_toggle.geometry (), Qbrush (qcolor (0, 0, 0)) # to mask image as Mask Self.setmask (Qbitmap (Self.pixmap))


Here I have no replacement variables, too much trouble, can see the algorithm on the line.
Let the PYQT program hide in the taskbar
To make the PYQT program not present in the taskbar, construct Qwidget set these properties

Self.setwindowflags (Qt.framelesswindowhint | Qt.windowstaysontophint | Qt.popup | Qt.tool)


let the PYQT program join the system tray, resource file use
pyqt Add tray menu is very easy, a few lines of code can

Create Pallet Self.icon = Qicon (": \icon.png")
 Self.trayicon = Qsystemtrayicon (self) self.trayIcon.setIcon (Self.icon) Self.trayIcon.setToolTip (U "QQ fault assistant") self.trayIcon.show ()
 # tray Bubble Message Self.trayIcon.showMessage (U "QQ fault assistant", U " QQ Fault Assistant has been on standby, enter the game can be Activated "")
 # tray Menu self.action = qaction (u "exit QQ pick up assistant", self, triggered = sys.exit) # TRIGGER Click to invoke Sys.exit () command, That is, exit Self.menu = Qmenu (self) self.menu.addAction (self.action) self.trayIcon.setContextMenu (Self.menu)

Originally I used the tray icon is an. ico file, the execution script can be displayed normally, but packaged into an EXE after the execution on the tray as a blank icon, compiled with the Python idle tool is also blank. After several attempts to discover: PYQT tray icon can not use the. ico file, otherwise it will show white space, the PNG format material will be no problem!
PYQT Resource File Packaging
QT uses a. qrc format for XML file management footage, which is also supported in PYQT by referencing the material in a resource file in a \xxx\xxx.png way.
Here I created a RESOURCES.QRC file

<! DOCTYPE rcc> <RCC version= "1.0" > <qresource> <file>icon.png</file> </qresource> < /rcc>


and use

PYRCC4 RESOURCES.QRC > resources.py


command to turn a resource file into a Python module and import resources into your code, you can use the image footage in this way

Self.icon = Qicon (": \icon.png")


Packaged as an executable program
This tool is for others, and certainly cannot be published as a PY script, I use Cx_freeze to package as an executable.
To do this, write a package command script convert2exe.py

#! Python #coding =gbk  # python exe script # # # Install Cx_freeze # Execute Python convert2exe.py build # will automatically generate builds directory, all files under it must be packaged #  I Mport sys from cx_freeze import setup, executable
 
base = None if Sys.platform = = "Win32":
  base = "Win32gui" 
bu Ildoptions = Dict (
  compressed = True)
 
Setup (
    name = "Zhaochaassistant", Version = "1.0", Description = "Zhaoch" Aassistant ", options = dict (Build_exe = buildoptions), executables = [Executable (" zhaochaassistant.py ", base = base, Icon = "Icon.ico")])


Finally execute a command

Python convert2exe.py Build

A build directory is created under the current path, and the packaged program is in one of the exe.win-amd64-2.7 directories, running EXE to execute, and Python no two. Unfortunately, this package is a bit too big, and the entire directory is up to 30M.

In order to let EXE program also has a good-looking icon, in the last line of the executables parameter in the specified icon = "Icon.ico", this icon is best to use the multiple pages of the. ico format (16x16,32x32,48x48 ...), Let the program in various display environment (desktop, folder) have a native display.

If you must use a separate resource when you package, add a include_files = [' Xxx.dat '] configuration to the buildoptions dictionary parameter. This will copy the Xxx.dat files in the Python script directory into the EXE directory when you pack them, and you'll have to copy them manually if you don't write them.

Tip: Python gets its own absolute path
Python has a magic variable can get the name of the script itself, but the conversion to the EXE after the variable invalidation, you have to use sys.executable to get the name of the executable program, can be used hasattr (SYS, "Frozen") to determine whether they have been packaged, Here is a convenient way to take the absolute path of the function:
Import sys def module_path (): If Hasattr (SYS, frozen): Return os.path.dirname Os.path.abspath (Unicode (sys.executable , sys.getfilesystemencoding ())) return Os.path.dirname (Os.path.abspath Unicode (__file__, Sys.getfilesystemencoding ()))

Conclusion

Python may be the best toy for programmers, and everything can be glued together, and it's a good idea to write little gadgets everyday.
Third-party modules in this article can be Google to obtain the download address, some libraries do not have Win7 64-bit original version (such as PIL), but can be
http://www.lfd.uci.edu/~gohlke/pythonlibs/
It is also very convenient to download other people to compile it well.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.