The short of it is that I have a widget, with source, written in Tk, specifically an analogue gauge, that I would like to use in a TKinter gui. Is this even possible? If so, how?

Thanks for any insight you might have.

Recommended Answers

All 9 Replies

Why wouldn't you be able to? Post the source.

Check Tkinter.Tcl command.

Why wouldn't you be able to? Post the source.

Here is the source of the tcl/tk guage that I want to use in Python:

$Tk::Gauge::VERSION = '0.3'; package Tk::Gauge; use 5.8.2; use Tk 804.027; use Tk::widgets qw/ Trace /; use base qw/ Tk::Derived Tk::Canvas /; use strict; Construct Tk::Widget 'Gauge'; # Class global definitions. my $id = 0; # needle ID my ( %band_defaults ) = ( -arccolor => 'white', -minimum => 0, -maximum => 100, -piecolor => 'white', -tag => '', ); # default band options my $d2r = 0.0174532; # degrees to radians my ( %needle_defaults ) = ( -arrowshape => [ 12, 23, 6 ], -color => 'black', -command => undef, -format => '%d', -id => 0, -radius => 96, -showvalue => 0, -tag => '', -title => '', -titlecolor => 'black', -titlefont => 'Helvetica-12', -titleplace => 'south', -variable => \my $var, -width => 5, ); # default needle options sub Populate { my ($self, $args) = @_; $self->SUPER::Populate($args); $self->ConfigSpecs(
        -background => [ 'SELF', 'background' , 'Background' , 'white' ],
        -bands => [ 'PASSIVE', 'bands' , 'Bands' , undef ],
        -bandplace => [ 'PASSIVE', 'bandPlace' , 'BandPlace' , 'underticks' ],
        -bandstyle => [ 'PASSIVE', 'bandStyle' , 'BandStyle' , 'band' ],
        -bandwidth => [ 'PASSIVE', 'bandWidth' , 'BandWidth' , 10 ],
        -caption => [ 'PASSIVE', 'caption' , 'Caption' , '' ],
        -captioncolor => [ 'PASSIVE', 'captionColor' , 'CaptionColor' , 'black' ],
        -extent => [ 'PASSIVE', 'extent' , 'Extent' , -270 ],
        -fill => [ 'PASSIVE', 'fill' , 'Fill' , 'white' ],
        -finetickcolor => [ 'PASSIVE', 'fineTickColor' , 'FineTickColor' , 'black' ],
        -finetickinterval => [ 'PASSIVE', 'fineTickInterval' , 'FineTickInterval' , undef ],
        -fineticklength => [ 'PASSIVE', 'fineTickLength' , 'FineTickLength' , 2 ],
        -finetickthickness => [ 'PASSIVE', 'fineTickThickness' , 'FineTickThickness' , 1 ],
        -from => [ 'PASSIVE', 'from' , 'From' , 0 ],
        -hubcolor => [ 'PASSIVE', 'hubColor' , 'HubColor' , '#ef5bef5bef5b' ],
        -huboutline => [ 'PASSIVE', 'hubOutline' , 'HubOutline' , '#ef5bef5bef5b' ],
        -hubplace => [ 'PASSIVE', 'hubPlace' , 'Hubplace' , 'overneedle' ],
        -hubradius => [ 'PASSIVE', 'hubRadius' , 'HubRadius' , 5 ],
        -majortickcolor => [ 'PASSIVE', 'majorTickColor' , 'MajorTickColor' , 'black' ],
        -majortickinterval => [ 'PASSIVE', 'majorTickInterval' , 'MajorTickInterval' , 10 ],
        -majorticklabelcolor => [ 'PASSIVE', 'majorTickLabelColor' , 'MajorTickLabelColor' , 'black' ],
        -majorticklabelfont => [ 'PASSIVE', 'majorTickLabelFont' , 'MajorTickLabelFont' , 'Helvetica-12' ],
        -majorticklabelformat => [ 'PASSIVE', 'majorTickLabelFormat', 'MajorTickLabelFormat', '%d' ],
        -majorticklabelpad => [ 'PASSIVE', 'majorTickLabelPad' , 'MajorTickLabelPad' , 10 ],
        -majorticklabelplace => [ 'PASSIVE', 'majorTickLabelPlace' , 'MajorTickLabelPlace' , 'inside' ],
        -majorticklabelscale => [ 'PASSIVE', 'majorTickLabelScale' , 'MajorTickLabelScale' , 1 ],
        -majorticklabelskip => [ 'PASSIVE', 'majorTickLabelSkip' , 'MajorTickLabelSkip' , undef ],
        -majorticklength => [ 'PASSIVE', 'majorTickLength' , 'MajorTickLength' , 10 ],
        -majortickthickness => [ 'PASSIVE', 'majorTickThickness' , 'MajorTickThickness' , 1 ],
        -margin => [ 'PASSIVE', 'margin' , 'Margin' , 10 ],
        -minortickcolor => [ 'PASSIVE', 'minorTickColor' , 'MinorTickColor' , 'black' ],
        -minortickinterval => [ 'PASSIVE', 'minorTickInterval' , 'MinorTickInterval' , undef ],
        -minorticklength => [ 'PASSIVE', 'minorTickLength' , 'MinorTickLength' , 5 ],
        -minortickthickness => [ 'PASSIVE', 'minorTickThickness' , 'MinorTickThickness' , 1 ],
        -needles => [ 'PASSIVE', 'needles' , 'Needles' , [{%needle_defaults}] ],
        -needlepad => [ 'PASSIVE', 'needlePad' , 'NeedlePad' , 0 ],
        -outline => [ 'PASSIVE', 'outline' , 'Outline' , 'black' ],
        -outlinewidth => [ 'PASSIVE', 'outlineWidth' , 'OutlineWidth' , 2 ],
        -start => [ 'PASSIVE', 'start' , 'Start' , 225 ],
        -style => [ 'PASSIVE', 'style' , 'Style' , 'chord' ],
        -to => [ 'PASSIVE', 'to' , 'To' , 100 ], ); $self->OnDestroy( [ \&delete_traces, $self ] ); } # end Populate sub ConfigChanged { my( $self, $args ) = @_; $self->delete( 'gauge', 'hub', 'ticks', 'caption' ); my $radius = $self->maxradius; $self->{ -maxradius } = $radius; my( $center_x, $center_y ) = $self->centerpoint; $self->configure( -width => 2 * $center_x, -height => 2 * $center_y - $self->cget( -margin ) / 2 ); # Create the main gauge. $self->createArc(
        ( $center_x - $radius, $center_y - $radius ),
        ( $center_x + $radius, $center_y + $radius ),
        -extent => $self->cget( -extent ),
        -fill => $self->cget( -fill ),
        -outline => $self->cget( -outline ),
        -start => $self->cget( -start ),
        -style => $self->cget( -style ),
        -tags => 'gauge',
        -width => $self->cget( -outlinewidth ), ); # Creat the hub. my $hub_place = $self->cget( -hubplace ); die "Invalid -hubplace '$hub_place': must be 'overneedle', 'underneedle or 'hide'." unless $hub_place =~ /^overneedle|underneedle|hide$/; if( $hub_place ne 'hide' ) { $self->createOval(
        ( $center_x - $self->cget( -hubradius ), $center_y - $self->cget( -hubradius ) ),
        ( $center_x + $self->cget( -hubradius ), $center_y + $self->cget( -hubradius ) ),
        -fill => $self->cget( -hubcolor ),
        -outline => $self->cget( -huboutline ),
        -tags => 'hub',
        ); } # Draw bands. my $from = $self->cget( -from ); my $to = $self->cget( -to ); my $bands = $self->cget( -bands ); if( $bands ) { foreach my $band ( @$bands ) { my(@margs, %ahsh, $args, @args); # fill in default band options not supplied by the user @margs = grep ! defined $band->{$_}, keys %band_defaults; %ahsh = %$band; # argument hash @ahsh{@margs} = @band_defaults{@margs}; # fill in missing values my( $arccolor, $min, $max, $piecolor, $tag ) = @ahsh{ qw/-arccolor -minimum -maximum -piecolor -tag / }; my $gext = $self->cget( -extent ); # gauge -extent my $gstart = $self->cget( -start ); # gauge -start my $ext = - ( $max - $min ) * ( $gext / ( $to - $from ) ); my $start = $gstart + $gext * ( $max - $from ) / ( $to - $from );
        my $radius4 = $radius - ( $self->cget( -bandwidth ) / 2 ); my $style = $self->cget( -bandstyle ); die "Invalid -bandstyle '$style': must be 'band' or 'pieslice'." unless $style =~ /^band|pieslice$/; $style = 'arc' if $style eq 'band';
        $self->createArc(
        ( $center_x - $radius4, $center_y - $radius4 ),
        ( $center_x + $radius4, $center_y + $radius4 ),
        -extent => $ext,
        -fill => $piecolor,
        -outline => $arccolor,
        -start => $start,
        -style => $style,
        -tags => [ 'bands', $tag ],
        -width => $self->cget( -bandwidth ),
        ); } # forend all bands } # ifend bands # Draw tick marks. my $start = $self->cget( -start ); my $extent = $self->cget( -extent ); my $tincr = ( $extent / ( $to - $from ) ); my $angle = $start - $tincr; for( my $gvalue = $from; $gvalue <= $to; $gvalue ++ ) { $angle += $tincr; my $theta = -$angle * $d2r; my( $x, $y ) = ( cos( $theta ) * $radius, sin( $theta ) * $radius ); $x += $center_x; $y += $center_y; my $major = 0; $major = ! ( $gvalue % $self->cget( -majortickinterval ) ); my $minor = 0; $minor = ! ( $gvalue % $self->cget( -minortickinterval ) ) if defined $self->cget( -minortickinterval ); my $fine = 0; $fine = ! ( $gvalue % $self->cget( -finetickinterval ) ) if defined $self->cget( -finetickinterval ); next unless $major or $minor or $fine; my $format = $self->cget( -majorticklabelformat ); my $scale = $self->cget( -majorticklabelscale ); my $place = $self->cget( -majorticklabelplace ); die "Invalid -majorticklabelplace '$place': must be 'inside', 'outside' or 'hide'." unless $place =~ /^inside|outside|hide$/; my $skip = 0; my $skipref = $self->cget( -majorticklabelskip ); if( defined $skipref ) { die "Invalid -majorticklabelskip '$skipref': must be an array reference." unless ref $skipref eq 'ARRAY'; foreach my $skipval ( @$skipref ) { next unless $skipval == $gvalue; $skip = 1; last; } } if( $major and $place ne 'hide' and not $skip ) { my $radius2; my $fw = $self->fontMeasure( $self->cget( '-majorticklabelfont' ), '0' ); if( $place eq 'outside' ) { $radius2 = $radius + ( length( $to * $scale ) / 2 * $fw ) + $self->cget( -majorticklabelpad ) ; } elsif( $place eq 'inside' ) { $radius2 = $radius - ( length( $to * $scale ) / 2 * $fw ) - $self->cget( -majorticklabelpad ) - $self->cget( -majorticklength ); } my( $x2, $y2 ) = ( cos( $theta ) * $radius2, sin( $theta ) * $radius2 ); $x2 += $center_x; $y2 += $center_y; my $tangle = sprintf( $format, $gvalue * $scale ); $self->createText( $x2, $y2, -text => $tangle, -fill => $self->cget( -majorticklabelcolor ), -tags => 'ticklabel' ); } if( $major or $minor or $fine ) { my $radius3; # order is important my $color; my $tag; my $width; if( $fine ) { $radius3 = $radius - $self->cget( -fineticklength ); $color = $self->cget( -finetickcolor ); $tag = 'finetick'; $width = $self->cget( -finetickthickness ); } if( $minor ) { $radius3 = $radius - $self->cget( -minorticklength ); $color = $self->cget( -minortickcolor ); $tag = 'minortick'; $width = $self->cget( -minortickthickness ); } if( $major ) { $radius3 = $radius - $self->cget( -majorticklength ); $color = $self->cget( -majortickcolor ); $tag = 'majortick'; $width = $self->cget( -majortickthickness ); } my( $x3, $y3 ) = ( cos( $theta ) * $radius3, sin( $theta ) * $radius3 ); $x3 += $center_x; $y3 += $center_y; $self->createLine( $x, $y, $x3, $y3,
        -fill => $color,
        -tags => $tag,
        -width => $width,
        ); } } # forend all ticks # Add the caption. $self->createText( $center_x, $self->cget( -margin ) + 2 * $radius,
        -fill => $self->cget( -captioncolor ),
        -text => $self->cget( -caption ),
        -tags => 'caption', ); # Trace the variables and setup callbacks associated with all the needles. my $needles = $self->cget( -needles ); if( $needles ) { $id = 'needle000000'; $self->delete_traces; foreach my $needle ( @$needles ) { $needle->{ -id } = $id++; $self->delete( $needle->{ -id } ); $self->traceVariable ( $needle->{ -variable } , 'w', [ \&tracew => $self, $needle ] ); if( defined $needle->{ -command } ) { $needle->{ -command_callback } = Tk::Callback->new( $needle->{ -command } ); } } } } # end ConfigChanged sub delete_traces { my( $self ) = @_; my $needles = $self->cget( -needles ); return unless defined $needles; foreach my $needle ( @$needles ) { $self->traceVdelete ( $needle->{ -variable } ) if defined $needle->{ -variable }; } } # end delete_traces sub setvalue { # draw needle(s) my( $self, $value, $needle ) = @_; # Fill in default needle options not supplied by the user. my(@margs, %ahsh, $args, @args); @margs = grep ! defined $needle->{$_}, keys %needle_defaults; %ahsh = %$needle; # argument hash @ahsh{@margs} = @needle_defaults{@margs}; # fill in missing values # Get needle options. my( $radius, $color, $cmd, $format, $vref, $width, $arrowshape, $showvalue, $title, $tcolor, $tfont, $tplace, $tag ) = @ahsh{ qw/ -radius -color -command -format -variable -width -arrowshape -showvalue -title -titlecolor -titlefont -titleplace -tag / }; my( $center_x, $center_y ) = $self->centerpoint; if( $value > $self->cget( -to ) ) { $value = $self->cget( -to ); } elsif( $value < $self->cget( -from ) ) { $value = $self->cget( -from ); } my( $x, $y ) = $self->radialpoint( $value, $radius ); $self->delete( $needle->{ -id } ); $self->createLine( $x, $y, $center_x, $center_y,
        -arrow => 'first',
        -arrowshape => $arrowshape,
        -fill => $color,
        -tags => [ 'needle', $needle->{ -id }, $tag ],
        -width => $width, ); my $hub_place = $self->cget( -hubplace ); $self->raise( 'hub', 'needle' ) if $hub_place eq 'overneedle'; $self->lower( 'hub', 'needle' ) if $hub_place eq 'underneedle'; if( $showvalue ) { my $fw = $self->fontMeasure( $self->cget( -majorticklabelfont ), '0' ); my $radius2 = $self->{ -maxradius } + $self->cget( -majorticklabelpad ) + ( $fw * length( $self->cget( -to ) ) ); ( $x, $y ) = $self->radialpoint( $value, $radius2 ); $value = sprintf( $format, $value ); $self->createText( $x, $y, -text => $value, -fill => $color, -tags => [ 'needlevalue', $needle->{ -id } ] ); } # Needle title. $x = $center_x; die "Invalid -titleplace '$tplace': must be 'north' or 'south'." unless $tplace =~ /^north|south$/; if( $tplace eq 'south' ) { $y = $center_y + $radius / 2; } elsif( $tplace eq 'north' ) { $y = $center_y - $radius / 2; } $self->createText( $x, $y, -text => $title, -fill => $tcolor, -font => $tfont , -tags => [ 'title', $needle->{ -id } ] ); my $bplace = $self->cget( -bandplace ); die "Invalid -bandplace '$bplace': must be 'underticks' or 'overticks'." unless $bplace =~ /^overticks|underticks$/; $self->raise( 'bands' ) if $bplace eq 'overticks'; } # end setvalue sub tracew { my ( $index, $value, $op, $self, $needle ) = @_; # Invoke the -command callback, if any, then move the needle. return unless defined $self; # if app is being destroyed return if $self->{_busy}; if ( $op eq 'w' ) { my $rc = 1; if( defined $needle->{ -command_callback } ) { $rc = $needle->{ -command_callback }->Call; } $self->setvalue( $value, $needle ) if $rc; return $value; } elsif ( $op eq 'r' ) { } elsif ( $op eq 'u' ) { $self->traceVdelete ( $needle->{-variable} ); } } # end tracew # Public methods. sub centerpoint { # coordinates of center of gauge my( $self ) = @_; $self->{ -maxradius } = $self->maxradius;; return ( $self->cget( -margin ) + $self->{ -maxradius } ) x 2; } # end centerpoint sub maxradius { # maximum needle radius including padding my( $self ) = @_; my $radius = 0; foreach my $needle ( @{ $self->cget( -needles ) } ) { $radius = $needle->{ -radius } if $needle->{ -radius } > $radius; } return $radius += $self->cget( -needlepad ); } # end maxradius sub radialpoint { # coordinates of a needle value relative to the gauge centerpoint my( $self, $value, $radius ) = @_; my $from = $self->cget( -from ); my $to = $self->cget( -to ); my $start = $self->cget( -start ); my $extent = $self->cget( -extent ); my $tincr = $extent / ( $to - $from ); my $angle = $start + ( ( $value - $from ) * $tincr ); $angle = -$angle * $d2r; my( $x, $y ) = ( cos( $angle ) * $radius, sin( $angle ) * $radius ); my( $center_x, $center_y ) = $self->centerpoint; $x += $center_x; $y += $center_y; return ( $x, $y ); } # end radialpoint 1; __END__

pyTony suggests using Tkinter.Tcl, but that seems to do just the opposite of what I need by calling a python function from tcl, unless I am misunderstanding its usage.

did you review this http://docs.python.org/library/tk.html?

Yes, I have spent some time reviewing that and numerous other documents prior to posting my question! I didn't even find a reference there for to.tcl or tk.eval.

Yeah, I often get very frustrated with the lack of documentation, or at least quality documentation on things. It seems like this would be pretty easy to write in python, but I guess the answer to whether or not you could directly run the tcl code in the python interpreter is no. However, and I have no experience with it, there is a jacl (javatcl) to jython converter I found on bytes:http://www-1.ibm.com/support/docview...id=swg24012144, unfortunately I don't know of any other direct converter/translator. Just out of curiosity, why did you write something in tcl?

Yeah, I often get very frustrated with the lack of documentation, or at least quality documentation on things. It seems like this would be pretty easy to write in python, but I guess the answer to whether or not you could directly run the tcl code in the python interpreter is no. However, and I have no experience with it, there is a jacl (javatcl) to jython converter I found on bytes:http://www-1.ibm.com/support/docview...id=swg24012144, unfortunately I don't know of any other direct converter/translator. Just out of curiosity, why did you write something in tcl?

I didn't write it but found it in a search. Couldn't find a python tk widget similar. New to python. I could port it but being new would take some time.

Maybe you should check Power MegaWidgets (easy_install pmw), here is one gauge written with those:
http://www.java2s.com/Code/Python/GUI-Pmw/GaugemadefromPmwMegaWidget.htm:

#Pmw copyright #Copyright 1997-1999 Telstra Corporation Limited, Australia #Copyright 2000-2002 Really Good Software Pty Ltd, Australia #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal #in the Software without restriction, including without limitation the rights #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the Software is furnished #to do so, subject to the following conditions: #The above copyright notice and this permission notice shall be included in all #copies or substantial portions of the Software. #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A #PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION #OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. from Tkinter import * import Pmw class Gauge(Pmw.MegaWidget): def __init__(self, parent=None, **kw): 
        # Define the options for the megawidget
        optiondefs = (
        ('min', 0, Pmw.INITOPT),
        ('max', 100, Pmw.INITOPT),
        ('fill', 'red', None),
        ('size', 30, Pmw.INITOPT),
        ('value', 0, None),
        ('showvalue', 1, None),
        )
        self.defineoptions(kw, optiondefs) 
        # Initialize the base class
        Pmw.MegaWidget.__init__(self, parent) 
        interior = self.interior() 
        # Create the gauge component
        self.gauge = self.createcomponent('gauge',
        (), None,
        Frame, (interior,),
        borderwidth=0)
        self.canvas = Canvas(self.gauge,
        width=self['size'], height=self['size'],
        background=interior.cget('background'))
        self.canvas.pack(side=TOP, expand=1, fill=BOTH, anchor=CENTER)
        self.gauge.grid() 
        # Create the scale component
        self.scale = self.createcomponent('scale',
        (), None,
        Scale, (interior,),
        command=self._setGauge,
        length=200,
        from_ = self['min'],
        to = self['max'],
        showvalue=self['showvalue'])
        self.scale.grid() 
        value=self['value']
        if value is not None:
        self.scale.set(value) 
        # Check keywords and initialize options
        self.initialiseoptions(Gauge) def _setGauge(self, value):
        self.canvas.delete('gauge')
        ival = self.scale.get()
        ticks = self['max'] - self['min']
        arc = (360.0/ticks) * ival
        xy = 3,3,self['size'],self['size']
        start = 90-arc
        if start < 0:
        start = 360 + start
        self.canvas.create_arc(xy, start=start, extent=arc-.001,
        fill=self['fill'], tags=('gauge',)) Pmw.forwardmethods(Gauge, Scale, 'scale') root = Tk() #root.option_readfile('optionDB') root.title('Gauge') Pmw.initialise() gauges = tuple(Gauge(root, fill=color, value=10*v, min=0, max=255)
        for v, color in enumerate(('red', 'blue', 'black', 'yellow', 'pink', 'gray'))) for g in gauges: g.pack(side=LEFT, padx=1, pady=10) root.mainloop()

I did little more clever creation for Gauge objects and packing them.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.