Advertisement
fernly

table-test-basic

Mar 16th, 2015
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.35 KB | None | 0 0
  1. import random
  2. import time
  3. from sortedcontainers import SortedDict
  4.  
  5. # Define the database. At this point it comprises a single SortedDict in
  6. # which the keys are rwt(8) "word" tokens, and the values are tuples
  7. # comprising ( word, int in 0-99, rft() flag string). Yes this is
  8. # redundant in having the word as both key and value but it simplifies
  9. # coding the data() method of the model.
  10.  
  11. DBM = SortedDict()
  12. DBK = None # keysview
  13. DBV = None # valuesview
  14.  
  15. DBS = 10000 # how many rows
  16.  
  17. # These functions are used to populate the database with
  18. # values that are kinda-sorta like the ones in my app.
  19.  
  20. def xdi(B,N,M):
  21.     '''
  22.            eXponential Distribution of Integers, XDI
  23.    Return a list of length N of integers with max value M, from an exponential
  24.    distribution with beta B.
  25.    '''
  26.     M = int(M) # just in case
  27.     # pre-allocate the list rather than building it with .append()
  28.     r = [0]*N
  29.     for j in range(N) :
  30.         r[j] = int( random.expovariate(B) ) % M
  31.     return r
  32.  
  33. RWTALPH = 'aeiouåáïbcdfghjklmnpqrstvwxyz_BCDFGHJKLMNPQRSTVWZ'
  34. def rwt(N):
  35.     '''
  36.            Random Word-like Token, RWT
  37.    Return a word-like token comprising N Latin-1 letters with an
  38.    emphasis on vowels.
  39.    '''
  40.     ii = xdi( 0.1, N, len(RWTALPH)-1 )
  41.     return ''.join( [ RWTALPH[i] for i in ii ] )
  42.  
  43. def rft():
  44.     '''
  45.            Random Flag Token
  46.    Return an 8-char token composed mostly of dashes with a sprinkle of Xs,
  47.    e.g. "---X--X-" or "XX------".
  48.  
  49.    '''
  50.     ii = xdi( 2, 8, 2 )
  51.     return ''.join( ['-X'[i] for i in ii ] )
  52.  
  53. # Clear the database, called before Refresh
  54. def clear_the_db() :
  55.     global DBM, DBK, DBV
  56.     DBM.clear()
  57.     DBK = None
  58.     DBV = None
  59.  
  60. # Rebuild the database, called on a Refresh.
  61.  
  62. def rebuild_the_db():
  63.     global DBM, DBK, DBV, DBS
  64.     '''
  65.    [re]populate the fake database:
  66.    * Create a vector of random numbers which will constitute
  67.      Column 2 and also pace the creation loop
  68.    * Clear the SortedDict and load it with DBS rows of fake data
  69.    * Recreate the keysview and valuesview
  70.    '''
  71.     col2 = xdi( 0.05, DBS, 100 )
  72.     clear_the_db()
  73.     for k in col2 :
  74.         w = rwt(8)
  75.         f = rft()
  76.         DBM[ w ] = ( w, k, f )
  77.     DBV = DBM.values()
  78.  
  79. # Define the Table Model, instrumented to count certain calls
  80.  
  81. from PyQt5.QtCore import Qt, QAbstractTableModel
  82.  
  83. class Model( QAbstractTableModel ):
  84.     def __init__ ( self, parent=None ) :
  85.         super().__init__( parent )
  86.         self.access_counts = [0, 0, 0]
  87.  
  88.     def rowCount( self, index ) :
  89.         global DBM
  90.         if index.isValid() : return 0
  91.         return len(DBM)
  92.  
  93.     def columnCount( self, index ) :
  94.         if index.isValid() : return 0
  95.         return 3
  96.  
  97.     def data(self, index, role ) :
  98.         global DBV
  99.         if role != Qt.DisplayRole :
  100.             return None
  101.         row = index.row()
  102.         col = index.column()
  103.         self.access_counts[col] += 1
  104.         return DBV[ row ][ col ]
  105.  
  106.     def clear_counts( self ) :
  107.         self.access_counts = [0, 0, 0]
  108.  
  109.     def counts( self ) :
  110.         return list( self.access_counts )
  111.  
  112. # Define the Table View, which at this point is quite minimal.
  113. # The View is instantiated from MainWindow, which also connects
  114. # the model to it.
  115.  
  116. from PyQt5.QtWidgets import QTableView
  117.  
  118. class View( QTableView ):
  119.     def __init__ ( self, parent=None ) :
  120.         super().__init__( parent )
  121.         self.setSortingEnabled( True )
  122.         self.sortByColumn( 0, Qt.AscendingOrder )
  123.  
  124. # Define the main window which is the visual face of this app.
  125.  
  126. from PyQt5.QtWidgets import (
  127.     QLabel,
  128.     QMainWindow,
  129.     QPushButton,
  130.     QVBoxLayout,
  131.     QHBoxLayout,
  132.     QWidget
  133.     )
  134.  
  135. class Main( QMainWindow ) :
  136.     def __init__ ( self ) :
  137.         super().__init__( )
  138.         self.times = [0, 0, 0]
  139.         clear_the_db() # make sure to start with 0 rows
  140.         self._uic() # all the layout stuff out of line
  141.         self.refresh_button.clicked.connect( self.do_refresh )
  142.  
  143.     # Slot called when Refresh is clicked:
  144.     # * clear the counts
  145.     # * start model reset
  146.     # * rebuild the DBM, timing it
  147.     # * end the model reset, timing that
  148.     # * update the labels displaying call counts and times
  149.  
  150.     def do_refresh( self ) :
  151.         self.table_model.clear_counts()
  152.         self.table_model.beginResetModel()
  153.         self.times[0] = time.process_time()
  154.         rebuild_the_db()
  155.         self.times[1] = time.process_time()
  156.         self.table_model.endResetModel()
  157.         QApplication.processEvents()
  158.         self.times[2] = time.process_time()
  159.         self.update_labels()
  160.  
  161.     def update_labels(self) :
  162.         [c0, c1, c2] = self.table_model.counts()
  163.         [t0, t1, t2] = self.times
  164.         self.c0_label.setText( str(c0) )
  165.         self.c1_label.setText( str(c1) )
  166.         self.c2_label.setText( str(c2) )
  167.         self.td_label.setText( '{:02.5f}'.format(t1-t0) )
  168.         self.tr_label.setText( '{:02.5f}'.format(t2-t1) )
  169.  
  170.     def _make_label( self, text='0' ) :
  171.         # just make a right-aligned label out of line
  172.         L = QLabel(text)
  173.         L.setAlignment( Qt.AlignRight | Qt.AlignVCenter )
  174.         return L
  175.  
  176.     def _uic( self ) :
  177.         # create the table
  178.         self.table_view = View( parent=self )
  179.         self.table_model = Model( parent=self )
  180.         self.table_view.setModel( self.table_model )
  181.         # create the refresh button, put it in an hbox by itself, for now
  182.         self.refresh_button = QPushButton( "Refresh" )
  183.         hb0 = QHBoxLayout()
  184.         hb0.addWidget(self.refresh_button, 0)
  185.         hb0.addStretch(1)
  186.         # create a set of labels to display counts of
  187.         # entry to the model.data() method and times
  188.         self.c0_label = self._make_label() # display role calls to column 0
  189.         self.c1_label = self._make_label() # 1
  190.         self.c2_label = self._make_label() # 2
  191.         self.tr_label = self._make_label() # time to reset the model
  192.         self.td_label = self._make_label() # time to rebuild the db
  193.         # build the row of call numbers
  194.         hb1 = QHBoxLayout()
  195.         hb1.addStretch(1) # push this row to the right
  196.         hb1.addWidget( self._make_label( 'Display role calls col 0:' ) )
  197.         hb1.addWidget( self.c0_label )
  198.         hb1.addStretch(0)
  199.         hb1.addWidget( self._make_label( 'col 1:' ) )
  200.         hb1.addWidget( self.c1_label )
  201.         hb1.addStretch(0)
  202.         hb1.addWidget( self._make_label( 'col 2:' ) )
  203.         hb1.addWidget( self.c2_label )
  204.         # build the row of times
  205.         hb2 = QHBoxLayout()
  206.         hb2.addStretch(1)
  207.         hb2.addWidget( self._make_label( 'Seconds to build DB:' ) )
  208.         hb2.addWidget( self.td_label )
  209.         hb2.addStretch(0)
  210.         hb2.addWidget( self._make_label( 'to reset model:' ) )
  211.         hb2.addWidget( self.tr_label )
  212.         # stack up the central layout
  213.         vb = QVBoxLayout()
  214.         vb.addLayout( hb0, 0 )
  215.         vb.addWidget( self.table_view, 1 )
  216.         vb.addLayout( hb1, 0 )
  217.         vb.addLayout( hb2, 0 )
  218.         # put all that in a widget and make the widget our central layout
  219.         wij = QWidget()
  220.         wij.setLayout( vb )
  221.         wij.setMinimumSize( 500, 500 )
  222.         self.setCentralWidget( wij )
  223.  
  224.  
  225. if __name__ == '__main__' :
  226.     from PyQt5.QtWidgets import QApplication
  227.     the_app = QApplication([])
  228.     main_window = Main()
  229.     main_window.show()
  230.     the_app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement