Не удается заставить полосу прокрутки работать в виде дерева PyGTK - PullRequest
1 голос
/ 28 сентября 2011

Сначала позвольте мне начать с того, что я много читаю здесь, и я нашел ответ, но не смог его найти.

Обычно я пытаюсь добавить полосу прокрутки, чтобы добавить ее в окно vbox. Я знаю это просто то, чего я не понимаю. Вот код (пожалуйста, игнорируйте операторы mysql, я еще не успел их почистить

#!/usr/bin/python
import pygtk
pygtk.require('2.0')
import gtk
import os
import sys
import MySQLdb
from Tkinter import *

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()
class Table_GUI:
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING

    def delete_event(self, widget, event, data=None):
        return False

    def destroy(self, widget, data=None):
        gtk.main_quit()

    def __init__(self):

        # create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_geometry_hints(min_width=400, min_height=200)

        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)

        self.vbox = gtk.VBox(False, 0)
        self.window.add(self.vbox)

        self.vbox.show()


        self.vbox.pack_start(self.scrolledwindow)

        self.frm_table = gtk.Frame()
        self.frm_table.set_shadow_type(gtk.SHADOW_NONE)
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.show_Table(oper_sys, ip_get)
        self.frm_table.show()
        self.vbox.pack_start(self.frm_table, True, True, 0)

        self.window.show()

    def show_Table(self, search_os, search_ip):

        ### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
        self.liststore = gtk.ListStore(str, str, str, str, str)


        if search_os != "" and search_ip !="":
        #Set up the queries. If the user has activted the checkbox, we need to include the ports in the query
            if ports_check == 1:
               pass
        #Otherwise just return the relevent data
            else:
                pass
        elif search_os != "" and search_ip == "":
            if ports_check == 1:
                pass
            else:
                pass
        elif search_os =="" and search_ip != "":
            if ports_check == 1:
                pass
            else:
                  pass
        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql query
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == 1:    
                ports.append(individual_result[3])
        #we are going to add blanks to the files in order to help readability
        #when putting this into the chart
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []

        index_counter = 0
        #this loop will check to see if the entry already exists in the cleaned variables. If it does, it 'omitts' them by inserting a blank line
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              #print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                #print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])

            if operating_list[index_counter] in cleaned_os_list and ip_list[index_counter] in cleaned_ip:
                #print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                #print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])

            if ip_list[index_counter] in cleaned_ip:
                #print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                #print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  

        #this section appends to the list store depending on whether the user wants to see the ports or not
        counter = 0
        for single_result in fetch_results:
            if ports_check == 1:
                self.liststore.append(
            [ cleaned_ip[counter], cleaned_os_list[counter], cleaned_host[counter], single_result[4], single_result[3] ]
            )
            else:
                self.liststore.append(
            [ single_result[0], single_result[1], single_result[2], "" , "" ]
            )
            counter +=1
        # Treeview
        self.treeview = gtk.TreeView()
        self.treeview.set_property("fixed-height-mode", False)
                #For some reason I can't get the scrolled window to work...
        self.scrolledwindow = gtk.ScrolledWindow()
        self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        # Columns
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        if ports_check == 1:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)

        self.treeview.set_model(self.liststore)
        self.treeview.set_headers_clickable(True)

        self.frm_table.add(self.treeview)
        self.treeview.show()


    #this function allows for the sorting of the columns
    #Given the way this works with the ports_check == 1, this will confuse the output
    def on_column_clicked(self, tc, user_data):
        self.liststore.set_sort_column_id(user_data, self.sort_order)

        if self.sort_order == gtk.SORT_ASCENDING:
            self.sort_order = gtk.SORT_DESCENDING
        else:
            self.sort_order = gtk.SORT_ASCENDING

        tc.set_sort_order(self.sort_order)

    def newColumn(self, title, index):
        self.cells[index] = gtk.CellRendererText()
        self.cells[index].set_property('cell-background-gdk', gtk.gdk.color_parse("#FFF"))

        self.columns[index] = gtk.TreeViewColumn(title, self.cells[index], text=index)
        self.columns[index].set_resizable(True)
        self.columns[index].set_reorderable(True)
        self.columns[index].set_sort_indicator(True)
        if(index == 0) : 
            self.columns[index].set_min_width(130)
        if (index == 1) : 
            self.columns[index].set_min_width(300)
        if (index == 2) :
            self.columns[index].set_min_width(200)
        self.columns[index].connect("clicked", self.on_column_clicked, index)
        self.treeview.insert_column(self.columns[index], -1)

    # The main function
    def main(self):
        gtk.main()

class createUI:
    def pushButton(self, parent):
        global ports_check, oper_sys, ip_get
        ports_check = display_ports.get()
        oper_sys = OS.get()
        ip_get = IP.get()
        gui = Table_GUI()
        gui.main()

    def __init__(self, parent):
        #export variables from this class so they are available in other classes

        global OS, IP, counter, display_ports

        self.panel1 = Frame(parent.title("main window"))
        self.panel1.pack()
        self.frame1 = Frame(self.panel1)
        #in the first frame, create the directions and the input boxes
        self.OS_label = Message(self.frame1, text="Search by operating system", justify=LEFT, width=180).pack(pady=2)
        OS = Entry(self.frame1)
        OS.pack()
        OS.focus_set()
        self.IP_label = Message(self.frame1, text="Search by IP", justify=LEFT, width=180).pack(pady=3)
        IP = Entry(self.frame1)
        IP.pack(pady=14, padx=60)    
        self.frame1.pack()

        self.frame5 = Frame(self.panel1)
        #set the variables used by the checkboxes to an IntVar so that they can be evaluated as off or on
        display_ports = IntVar()
        ports_checkbutton = Checkbutton(self.frame5, text='Display Ports', onvalue = 1, offvalue = 0, variable=display_ports, width=10)
        ports_checkbutton.pack(side=LEFT)
        self.frame5.pack()

        self.frame6 = Frame(self.panel1)
        #lambda was used so that the button does not execute the addToDB class before click. addToDB requires an argument and self.database_button didn't work
        self.database_button = Button(self.frame6, text="Get results!")
        self.database_button.pack()


        self.database_button.configure(command=lambda btn = self.database_button: self.pushButton(btn))

        self.quit_button = Button(self.frame6, text="Get me outta here", command=self.panel1.quit).pack()             
        self.frame6.pack()

if __name__ == "__main__":
    root = Tk()

    ui = createUI(root)
    ui.panel1.mainloop() 

Там вы увидите следующее:

# For some reason I can't get the scrolled window to work...
self.scrolledwindow = gtk.ScrolledWindow()
self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

Когда я попытался прикрепить его через

self.scrolledwindow.add_with_viewport(self.treeview)

Я получаю сообщение

GtkWarning: Attempting to add a widget with type GtkTreeView to a container of type GtkFrame, but the widget is already inside a container of type GtkViewport

Я зашел на страницу часто задаваемых вопросов, но я действительно не понял, что это говорит мне.

Если я попытаюсь установить self.window, я получу:

GtkWarning: Can't set a parent on a toplevel widget
self.scrolledwindow.add_with_viewport(self.window)

Тот довольно понятен

Если я попытаюсь добавить его к vbox, я получу:

GtkWarning: IA__gtk_scrolled_window_add_with_viewport: assertion `child->parent == NULL' failed[/quote]

Я не ищу халяву, но надеюсь, что кто-то может помочь мне указать верное направление. (как вы можете видеть, я не придумаю сценарий «Можете ли вы сделать мне программу, которая делает X»)

---> Новый интерфейс только для GTK ниже <---- </p>

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk
import gtk
import os
import sys
import MySQLdb

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()
#---------------------------------------------------------------
class Application(gtk.Window):
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING
####################
    def __init__(self):
        gtk.Window.__init__( self )
        self.set_title("Netowrk Scanner")

        self.create_widgets()
        self.connect_signals()

        #self.window.show_all()
        self.show_all()
        gtk.main()
#####################
    def create_widgets(self):
        #Ask the user to search by operating system
        self.vbox = gtk.VBox(spacing=10)
        self.operating_system_label_hbox_1 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Operating System :")
        self.operating_system_label_hbox_1.pack_start(self.label)

        #Set a check box so the user can choose to display ports
        self.ports_hbox_8 = gtk.HBox(spacing=10)
        self.ports_check = gtk.CheckButton("Display Ports")
        self.ports_hbox_8.pack_start(self.ports_check)
        self.halign_ports = gtk.Alignment(0,1,1,0)
        self.halign_ports.add(self.ports_hbox_8)

        self.os_entry_hbox_2 = gtk.HBox(spacing=10)
        self.OS = gtk.Entry()
        self.os_entry_hbox_2.pack_start(self.OS)

        self.hostname_label_hbox_3 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Hostname:")
        self.hostname_label_hbox_3.pack_start(self.label)

        self.hostname_entry_hbox_4 = gtk.HBox(spacing=10)
        self.HOSTNAME = gtk.Entry()
        self.hostname_entry_hbox_4.pack_start(self.HOSTNAME)

        self.ip_label_hbox_5 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by IP:")
        self.ip_label_hbox_5.pack_start(self.label)

        self.ip_entry_hbox_6 = gtk.HBox(spacing=10)
        self.IP = gtk.Entry()
        self.ip_entry_hbox_6.pack_start(self.IP)

        self.buttons_hbox_7 = gtk.HBox(spacing=10)
        self.button_ok = gtk.Button("Get Results!")
        self.buttons_hbox_7.pack_start(self.button_ok)
        self.button_exit = gtk.Button("Get me Outta Here!")
        self.buttons_hbox_7.pack_start(self.button_exit)

        #The order in which you pack_start a widget is the order in which it is displayed on the screen
        self.vbox.pack_start(self.operating_system_label_hbox_1)
        self.vbox.pack_start(self.os_entry_hbox_2)
        self.vbox.pack_start(self.hostname_label_hbox_3)
        self.vbox.pack_start(self.hostname_entry_hbox_4)
        self.vbox.pack_start(self.ip_label_hbox_5)
        self.vbox.pack_start(self.ip_entry_hbox_6)
        self.vbox.pack_start(self.halign_ports, False, False, 3)
        self.vbox.pack_start(self.buttons_hbox_7)

        self.add(self.vbox)
##########################
    def connect_signals(self):
        #Have the buttons start 'listening' for user interaction
        self.button_ok.connect("clicked", self.button_click)
        self.button_exit.connect("clicked", self.exit_program)

    def button_click(self, clicked):
        #This function gets the values of the input boxes as well as the check box
        #And then passes them to the show_table function so it can get the correct results from the database
        global ports_check, os, ip, hostname
        os = self.OS.get_text()
        ip = self.IP.get_text()
        hostname = self.HOSTNAME.get_text()
        ports_check = self.ports_check.get_active()
        self.frm_table = gtk.Window()
        self.frm_table.set_title("Network scan results")
        #Change the background to white instead of grey
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.frm_table.show()
        self.show_Table(os, ip, hostname)
############################     

    def show_Table(self, search_os, search_ip, search_hostname):
    ### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
        self.liststore = gtk.ListStore(str, str, str, str, str)
        #If the user is running a search on the hostname run these queries
        if search_hostname != "":
            if ports_check == True:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_hostname))
            #Otherwise just return the relevent data
            else:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_hostname))


        #If the user has specified the IP and the OS to search, run this query  
        if search_os != "" and search_ip !="":
        #Set up the queries. If the user has activated the checkbox, we need to include the ports in the query
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_os, search_ip))
        #Otherwise just return the relevent data
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_os, search_ip))
        #If the user has specified an OS but not an IP run this
        elif search_os != "" and search_ip == "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_os)
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_os)
        #If the user has specified an IP but not an OS run this
        elif search_os =="" and search_ip != "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_ip)
            else:
                 cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_ip)


        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql query
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == True:    
                ports.append(individual_result[3])
        #we are going to add blanks to the files in order to help readability
        #when putting this into the chart
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []

        index_counter = 0
        #this loop will check to see if the entry already exists in the cleaned variables. If it does, it 'omitts' them by inserting a blank line
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              #print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                #print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])

            if operating_list[index_counter] in cleaned_os_list and ip_list[index_counter] in cleaned_ip:
                #print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                #print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])

            if ip_list[index_counter] in cleaned_ip:
                #print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                #print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  

        #this section appends to the list store depending on whether the user wants to see the ports or not
        counter = 0
        for single_result in fetch_results:
            if ports_check == True:
                self.liststore.append(
            [ cleaned_ip[counter], cleaned_os_list[counter], cleaned_host[counter], single_result[4], single_result[3] ]
            )
            else:
                self.liststore.append(
            [ single_result[0], single_result[1], single_result[2], "" , "" ]
            )
            counter +=1
        # Treeview
        self.treeview = gtk.TreeView()
        #In lieu of getting the scroll bar to work, force a max height requirement on creation
        self.treeview.set_property('height-request', 600)
        # Columns
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        #I only want the ports columns to show if the user requests it because this calls different mysql queries
        if ports_check == True:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)

        #put the liststore inside of the tree view    
        self.treeview.set_model(self.liststore)
        self.treeview.set_headers_clickable(True)
        #Still can't get the scroll bar to work properly so leaving them commented out
        #self.scrolledwindow = gtk.ScrolledWindow()
        #self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        #add the tree view to the frm_table
        self.frm_table.add(self.treeview)
        self.treeview.show()

##########################        
    def on_column_clicked(self, tc, user_data):
        #This function allows the columns to be resorted upon click
        self.liststore.set_sort_column_id(user_data, self.sort_order)

        if self.sort_order == gtk.SORT_ASCENDING:
            self.sort_order = gtk.SORT_DESCENDING
        else:
            self.sort_order = gtk.SORT_ASCENDING

        tc.set_sort_order(self.sort_order)
###########################
    def newColumn(self, title, index):
        #This function cleans up code because I want these options on all of the columns
        #This code block would have to be duplicated for each column otherwise...
        self.cells[index] = gtk.CellRendererText()
        self.cells[index].set_property('cell-background-gdk', gtk.gdk.color_parse("#FFF"))

        self.columns[index] = gtk.TreeViewColumn(title, self.cells[index], text=index)
        self.columns[index].set_resizable(True)
        self.columns[index].set_reorderable(True)
        self.columns[index].set_sort_indicator(True)
        if(index == 0) : 
            self.columns[index].set_min_width(130)
        if (index == 1) : 
            self.columns[index].set_min_width(300)
        if (index == 2) :
            self.columns[index].set_min_width(200)
        self.columns[index].connect("clicked", self.on_column_clicked, index)
        self.treeview.insert_column(self.columns[index], -1)

    # The main function
########################
    def exit_program(self, widget, callback_data=None):
        gtk.main_quit()
#---------------------------------------------
if __name__ == "__main__":
    app = Application() 
    database_connection.commit()
    cursor.close()
    database_connection.close()

---> конец нового интерфейса <--- </p>

У меня все еще проблемы с полосами прокрутки. Я подозреваю, что так я добавляю виджеты в контейнеры.

ПРИМЕЧАНИЕ. Я удалил операторы mysql из первого графического интерфейса, чтобы сэкономить место на диске

Ответы [ 2 ]

2 голосов
/ 29 сентября 2011

Единственное отличие моего рабочего кода в том, что я НЕ использую "add_with_viewport":

    swH = gtk.ScrolledWindow()
    swH.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    swH.add(treeviewH)

Работает нормально. Пожалуйста, попробуйте и скажите мне, если все в порядке. Если нет, я буду копать дальше.


EDIT

Попробуйте этот пример, адаптируйте его к данным вашей БД (я не могу запустить вашу программу, потому что у меня нет базы данных) и наслаждайтесь!

#!/usr/bin/env python
# -*- Encoding: Latin-1 -*-

import pygtk
pygtk.require('2.0')
import gtk

def window():

    win = gtk.Window ()
    win.set_default_size(300, 150)
    win.set_position(gtk.WIN_POS_CENTER)
    win.connect ('delete_event', gtk.main_quit)

    cols = ['Date', 'Index', 'Program', 'Comments']
    sequence        = [str] * len(cols)
    starStore       = gtk.TreeStore( * sequence)
    starView        = gtk.TreeView(starStore)       
    starView.cell   = [None] * len(cols)
    tvcolumn        = [None] * len(cols)
    for colnum, col in enumerate(cols):
        starView.cell[colnum] = gtk.CellRendererText()
        tvcolumn[colnum] = gtk.TreeViewColumn(col, starView.cell[colnum])
        tvcolumn[colnum].add_attribute(starView.cell[colnum], 'text', colnum)
        starView.append_column(tvcolumn[colnum])

    scrollTree = gtk.ScrolledWindow()
    scrollTree.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
    scrollTree.add(starView)
    win.add(scrollTree)

    data = [['2010', '123', 'P02', 'Initial'], 
            ['2008', '456', 'P08', 'not finished'],
            ['2007', '456', 'P08', 'not finished'],
            ['2006', '456', 'P08', 'not finished'],  #  copy and paste a line to add, delete a line to shorten the treeview. The scollbar appears when needed.
            ['2005', '456', 'P08', 'not finished'],
            ['2004', '456', 'P08', 'not finished'],
            ['2001', '999', 'P999', 'A space Odissey']]

    for line in data:
        mother = starStore.append(  None, [line[0], line[1], line[2], line[3]])

    win.show_all()
    gtk.main()

if __name__ == '__main__':
    window()
1 голос
/ 01 октября 2011

Большое вам спасибо за это!После некоторой тренировки я смог адаптировать свою программу под вашим руководством!

Если кому-то это интересно, я выкладываю приведенный ниже код для полноты

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk
import gtk
import os
import sys
import MySQLdb

database_connection = MySQLdb.connect('localhost', 'root', '', 'nmap');
cursor = database_connection.cursor()

class Application(gtk.Window):
    cells = {}
    columns = {}
    sort_order = gtk.SORT_ASCENDING
####################
    def __init__(self):
        gtk.Window.__init__( self )
        self.set_title("Netowrk Scanner")
        self.set_position(gtk.WIN_POS_CENTER)
        self.create_widgets()
        self.connect_signals()

        #self.window.show_all()
        self.show_all()
        gtk.main()
##################        
    def create_widgets(self):
        #Ask the user to search by operating system
        self.vbox = gtk.VBox(spacing=10)
        self.operating_system_label_hbox_1 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Operating System :")
        self.operating_system_label_hbox_1.pack_start(self.label)

        #Set a check box so the user can choose to display ports
        self.ports_hbox_8 = gtk.HBox(spacing=10)
        self.ports_check = gtk.CheckButton("Display Ports")
        self.ports_hbox_8.pack_start(self.ports_check)
        self.halign_ports = gtk.Alignment(0,1,1,0)
        self.halign_ports.add(self.ports_hbox_8)

        self.os_entry_hbox_2 = gtk.HBox(spacing=10)
        self.OS = gtk.Entry()
        self.os_entry_hbox_2.pack_start(self.OS)

        self.hostname_label_hbox_3 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by Hostname:")
        self.hostname_label_hbox_3.pack_start(self.label)

        self.hostname_entry_hbox_4 = gtk.HBox(spacing=10)
        self.HOSTNAME = gtk.Entry()
        self.hostname_entry_hbox_4.pack_start(self.HOSTNAME)

        self.ip_label_hbox_5 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Search by IP:")
        self.ip_label_hbox_5.pack_start(self.label)

        self.ip_entry_hbox_6 = gtk.HBox(spacing=10)
        self.IP = gtk.Entry()
        self.ip_entry_hbox_6.pack_start(self.IP)

        self.buttons_hbox_7 = gtk.HBox(spacing=10)
        self.button_ok = gtk.Button("Get Results!")
        self.buttons_hbox_7.pack_start(self.button_ok)
        self.button_exit = gtk.Button("Get me Outta Here!")
        self.buttons_hbox_7.pack_start(self.button_exit)

        #The order in which you pack_start a widget is the order in which it is displayed on the screen
        self.vbox.pack_start(self.operating_system_label_hbox_1)
        self.vbox.pack_start(self.os_entry_hbox_2)
        self.vbox.pack_start(self.hostname_label_hbox_3)
        self.vbox.pack_start(self.hostname_entry_hbox_4)
        self.vbox.pack_start(self.ip_label_hbox_5)
        self.vbox.pack_start(self.ip_entry_hbox_6)
        self.vbox.pack_start(self.halign_ports, False, False, 3)
        self.vbox.pack_start(self.buttons_hbox_7)

        self.add(self.vbox)
##########################
    def connect_signals(self):
        #Have the buttons start 'listening' for user interaction
        self.button_ok.connect("clicked", self.button_click)
        self.button_exit.connect("clicked", self.exit_program)
########################
    def button_click(self, clicked):
        #This function gets the values of the input boxes as well as the check box
        #And then passes them to the show_table function so it can get the correct results from the database
        global ports_check, os, ip, hostname
        os = self.OS.get_text()
        ip = self.IP.get_text()
        hostname = self.HOSTNAME.get_text()
        ports_check = self.ports_check.get_active()

        self.show_Table(os, ip, hostname)
##############        
    def show_Table(self, search_os, search_ip, search_hostname):
    ### Create the table
        # List of items to display which represent IP, OS, DNS, Port number and Port description
         # Columns
        if ports_check == True:
            cols = ['IP Address', 'Operating System', 'Hostname', 'Ports', 'Protocol Name']
        else:
            cols = ['IP Address', 'Operating System', 'Hostname']
        """    
        self.newColumn("IP Address", 0)
        self.newColumn("Operating System", 1)
        self.newColumn("Hostname",2)
        #I only want the ports columns to show if the user requests it because this calls different mysql queries
        if ports_check == True:
            self.newColumn("Ports", 3)
            self.newColumn("Protocol name", 4)
        """

        sequence = [str] * len(cols)
        self.treestore = gtk.TreeStore( * sequence)
        self.treestore.connect("rows-reordered", self.on_column_clicked)
        self.treeview = gtk.TreeView(self.treestore)
        self.treeview.cell = [None] * len(cols)
        self.treeview_column = [None] * len(cols)

        for column_number, col in enumerate(cols):
            self.treeview.cell[column_number] = gtk.CellRendererText()
            self.treeview_column[column_number] = gtk.TreeViewColumn(col, self.treeview.cell[column_number])
            self.treeview_column[column_number].add_attribute(self.treeview.cell[column_number], 'text', column_number)
            self.treeview_column[column_number].set_resizable(True)
            self.treeview_column[column_number].set_reorderable(True)
            self.treeview_column[column_number].set_sort_indicator(True)
            self.treeview_column[column_number].set_sort_column_id(column_number)
            self.treeview.append_column(self.treeview_column[column_number])

        self.scrollTree = gtk.ScrolledWindow()
        self.scrollTree.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.scrollTree.add(self.treeview)

        #If the user is running a search on the hostname run these queries
        if search_hostname != "":
            if ports_check == True:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_hostname))
            #Otherwise just return the relevent data
            else:
                    cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                        JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                        JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                        JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                        JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                        WHERE DNS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_hostname))


        #If the user has specified the IP and the OS to search, run this query  
        if search_os != "" and search_ip !="":
        #Set up the queries. If the user has activated the checkbox, we need to include the ports in the query
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % (search_os, search_ip))
        #Otherwise just return the relevent data
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' and Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % (search_os, search_ip))
        #If the user has specified an OS but not an IP run this
        elif search_os != "" and search_ip == "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_os)
            else:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE OS_Name LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_os)
        #If the user has specified an IP but not an OS run this
        elif search_os =="" and search_ip != "":
            if ports_check == True:
                cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name, Port_Description, Open_Port FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address ), Open_Port" % search_ip)
            else:
                 cursor.execute("SELECT DISTINCT Computer_IP_Address, OS_Name, DNS_Name FROM Computer_Ports AS CP \
                    JOIN Computer_Info AS CI ON ( CP.Computer_ID = CI.Computer_ID ) \
                    JOIN Ports_Table AS PT ON ( CP.Port_ID = PT.Port_ID ) \
                    JOIN OS_Table AS OS ON ( CI.Computer_ID = OS.OS_ID ) \
                    JOIN Port_Description AS PS ON ( PT.Open_Port = PS.Port_Number ) \
                    WHERE Computer_IP_Address LIKE '%%%s%%' ORDER BY inet_aton( Computer_IP_Address )" % search_ip)

        #get the results and prepare to put them inside of lists
        fetch_results = cursor.fetchall()
        host_name_list = []
        operating_list = []
        ip_list = []
        ports = []
        #The element chosen to append to each list based on the order of retrieval in the mysql query
        for individual_result in fetch_results:
            ip_list.append(individual_result[0])
            operating_list.append(individual_result[1])    
            host_name_list.append(individual_result[2])
            if ports_check == True:    
                ports.append(individual_result[3])
        #we are going to add blanks to the files in order to help readability
        #when putting this into the chart
        cleaned_host =[]
        cleaned_ip = []
        cleaned_os_list = []

        index_counter = 0
        #this loop will check to see if the entry already exists in the cleaned variables. If it does, it 'omitts' them by inserting a blank line
        while index_counter < len(host_name_list):
            if host_name_list[index_counter] in cleaned_host:
              #print "found a duplicate in HOST....OMITTING"
              cleaned_host.append("")
            else:
                #print "adding ", host_name_list[index_counter]  
                cleaned_host.append(host_name_list[index_counter])

            if operating_list[index_counter] in cleaned_os_list and ip_list[index_counter] in cleaned_ip:
                #print "found a duplicate in OPERATING....OMITTING"
                cleaned_os_list.append("")
            else:
                #print "adding ", operating_list[index_counter]     
                cleaned_os_list.append(operating_list[index_counter])

            if ip_list[index_counter] in cleaned_ip:
                #print "Found a duplicate in IP.... OMITTING "
                cleaned_ip.append("")
            else:
                #print "adding ", ip_list[index_counter]     
                cleaned_ip.append(ip_list[index_counter])
            index_counter +=1  

        #this section appends to the list store depending on whether the user wants to see the ports or not
        counter = 0
        for single_result in fetch_results:
            if ports_check == True:
                self.treestore.append( None,
            [ cleaned_ip[counter], cleaned_os_list[counter], cleaned_host[counter], single_result[4], single_result[3] ]
            )

            else:

                self.treestore.append(None,
            [ single_result[0], single_result[1], single_result[2] ]
            )
            counter +=1


        self.frm_table = gtk.Window()
        self.frm_table.set_default_size(600, 800)
        self.frm_table.set_title("Network scan results")
        #Change the background to white instead of grey
        self.frm_table.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#fff'))
        self.frm_table.add(self.scrollTree)
        self.frm_table.show_all()
###################### 
    def on_column_clicked(self, col1, col2, col3, col4 ):
        #This function allows the columns to be resorted upon click

        if self.sort_order == gtk.SORT_ASCENDING:
            self.sort_order = gtk.SORT_DESCENDING
        else:
            self.sort_order = gtk.SORT_ASCENDING

        #tc.set_sort_order(self.sort_order) 
###############        
    def exit_program(self, widget, callback_data=None):
        gtk.main_quit()
#---------------------------------------------
if __name__ == "__main__":
    app = Application() 
    database_connection.commit()
    cursor.close()
    database_connection.close()
...