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.
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.
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.
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.