pyqgis plugin change QDialog to QMainWindow - qmainwindow

I have a plugin window is QDialog, but I want to add QMenubar or QStatusBar
I have tried to find a way to convert QDialog to QMainWindow, but there is no result,
So I try to add QMenubar in QDialog again and everything works fine
Until the position of the object I added to the layout screen ran to the upper left corner.
I am not a native English speaker
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
#建立menuBar的父節點物件
file_menu = QMenu("File")
#建立一個
open_action = QAction("Open",file_menu)
open_action.setShortcut('Alt+F4')
#把剛才建立的open action 加入file 節點
file_menu.addAction(open_action)
#建立一個menubar物件
menubar = QMenuBar(self.dlg)
#將父節點加入menubar
menubar.addMenu(file_menu)
#將self.dlg的menubar設定為menubar物件
self.dlg.setMenuBar(menubar)
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
pass

Related

Change filepath of an image using command

I have written some code which takes a date of birth and calculates the correct Chinese horoscope animal (rat, dog etc.). I would like to add a gui whereby, when the user hits calculate, the gui shows a photo of the appropriate animal. To do that I think I have to make the file path for an image change within the command definition, but can't find a way to do this. I have simplified the code as far as possible below:
x = Tk()
x.state('zoomed')
def find_animal():
animal = 'tiger' # I've left out the actual calculation part
picture.place(relx=0.4, rely=0.5)
b = Button(x, text='Calculate', command=find_animal)
b.place(relx=0.5, rely=0.3)
file_path = 'rabbit.png'
pic = PhotoImage(file=file_path)
picture = Label(x, image=pic)
x.mainloop()
The thing I'm hoping to do is somehow alter the file_path variable within the find_animal function so that the image displayed changes from rabbit to tiger
You can use pic.config() to change the image path inside find_animal():
def find_animal():
animal = 'tiger' # I've left out the actual calculation part
pic.config(file=animal+".png")
picture.place(relx=0.4, rely=0.5)

Coded UI test is not running while setting the UIElementText in the Playback

I have recorded the coded UI test using the VS2015 Coded UI Test builder. based on my recording the following function is created for my test method,
public void RecordedMethod1()
{
#region Variable Declarations
WpfText uIItemText = this.UIMainWindowWindow.UIAddNewRowControlCustom.UIGridCellCustom.UIItemText;
WpfEdit uIItemEdit = this.UIMainWindowWindow.UIAddNewRowControlCustom.UIGridCellCustom.UIItemEdit;
WpfText uIItemText1 = this.UIMainWindowWindow.UIAddNewRowControlCustom.UIGridCellCustom1.UIItemText;
#endregion
// Double-Click label
Mouse.DoubleClick(uIItemText, new Point(73, 3));
//// Failed in the following line and the test is not running after that.
// Type 'aaa' in text box
uIItemEdit.Text = this.RecordedMethod1Params.UIItemEditText;
// Double-Click label
Mouse.DoubleClick(uIItemText1, new Point(79, 10));
// Type 'bbb' in text box
uIItemEdit.Text = this.RecordedMethod1Params.UIItemEditText1;
// Type '{Enter}' in text box
Keyboard.SendKeys(uIItemEdit, this.RecordedMethod1Params.UIItemEditSendKeys, ModifierKeys.None);
}
After reaching the line to set the recorded value to the uiEditItem.Text the test case is not running further cased the failure in the test case.
I have googled for the solution and have found a one that says, you need to rewrite the test cases with the Kebord.SendKeys instead of directly setting the value to the Text property of the EditItem.
By this way I have made my code changes at the line as follows and its working.
// Type 'aaa' in text box
//uIItemEdit.Text = this.RecordedMethod1Params.UIItemEditText;
// Replaced the above line with the SenKeys
Keyboard.SendKeys(this.RecordedMethod1Params.UIItemEditText);
Is that the only solution for this problem (Manullay rewrite the test methods by using the SendKeys method instead of directly assigning a value to the uiEditItem.Text property) ? If not, please provide the feasible solution for this.

refresh the textScrollList in maya with Python

I have an array with lights , everytime I create a light it stores is my array.
I have a textScrollList that displays all lights in my Array.
When I add lights , it doesn't refersh the textScrollList.
Can someone tell me how I can do this , so everytime I make a light it display it in the textScrollList. Or with a refresh button.
Thanks !
Code I have now :
import maya.cmds as cmds
lights=[]
myWindow = cmds.window(title='My Lights', wh=(200,400),sizeable =False )
cmds.columnLayout()
cmds.showWindow(myWindow)
LightsButton = cmds.button(label='Make Lights', command = "makeLights()", width =200,height = 25,align='center')
def makeLights():
lights.append(cmds.shadingNode('aiAreaLight', asLight=True))
LightSelector = cmds.textScrollList( numberOfRows=8, allowMultiSelection=True,append=(lights), showIndexedItem=4, selectCommand = 'selectInTextList()' )
You can add a function that will refresh the list with the lights. This can be called after you create a new light so it adds to the list. You can also add a refresh button to call this same function in case you add/delete lights in the scene, and it will update properly.
You don't need to add the lights to a list and keep track of it. Instead you can use cmds.ls() to collect all the lights in the scene. Unless you really do need the list for some reason, it's easy to edit the example below to use it:
import maya.cmds as cmds
# Clear the listview and display the current lights in the scene.
def refreshList():
# Clear all items in list.
cmds.textScrollList(lightSelector, e=True, removeAll=True)
# Collect all lights in the scene.
allLights = cmds.ls(type='aiAreaLight')
# Add lights to the listview.
for obj in allLights:
cmds.textScrollList(lightSelector, e=True, append=obj)
# Create a new light and add it to the listview.
def makeLights():
lights.append(cmds.shadingNode('aiAreaLight', asLight=True))
refreshList()
def selectInTextList():
# Collect a list of selected items.
# 'or []' converts it to a list when nothing is selected to prevent errors.
selectedItems = cmds.textScrollList(lightSelector, q=True, selectItem=True) or []
# Use a list comprehension to remove all lights that no longer exist in the scene.
newSelection = [obj for obj in selectedItems if cmds.objExists(obj)]
cmds.select(newSelection)
# Create window.
myWindow = cmds.window(title='My Lights', wh=(200,400), sizeable=False)
cmds.columnLayout()
cmds.showWindow(myWindow)
# Create interface items.
addButton = cmds.button(label='Make Lights', command='makeLights()', width=200, height=25, align='center')
lightSelector = cmds.textScrollList(numberOfRows=8, allowMultiSelection=True, append=cmds.ls(type='aiAreaLight'), showIndexedItem=4, selectCommand='selectInTextList()')
refreshButton = cmds.button(label='Refresh list', command='refreshList()', width=200, height=25, align='center')
Hope that helps.

RPS, windows Form & Revit API (Python)

I've been trying to build a form to create and delete Revit print Sets.
I've 2 main issues:
1) I'm able to create a print set but I cannot access its content unless I restart the Form. I get the errors below (depending if I'm defining the view_set variable or not)
List_object_has_no_attribute_Views
Local_variable_referenced_before_assignment
This is the code of the function to display the sheets of the selected Print Set
def DisplaySheetsInSet (self, sender, args):
self.curItem = CurrentSetsListBox.SelectedItem
PrintSetForm_Load
try:
view_set=[]
for i in PrintSetForm.ViewSets:
if i.Name == str(self.curItem):
view_set = i
else:
continue
Sheets=[sheet.Name for sheet in view_set.Views]
SheetsLb.BeginUpdate()
SheetsLb.Items.Clear()
for sheet in Sheets:
SheetsLb.Items.Add(sheet)
SheetsLb.EndUpdate()
except Exception as e:
popup (str(e)
2) I'm able to delete print sets once. If I try do delete another one I get the following error and I need to restart the form ( code for the function that deletes the print sets shown below)
The_referenced_object_is_not_valid
def DelPrintSet(self, sender, args):
self.curItem = CurrentSetsListBox.SelectedItems
t = Transaction (doc, 'Delete printset')
t.Start()
for viewset in PrintSetForm.ViewSets:
if viewset.Name in [str(item) for item in self.curItem]:
doc.Delete(viewset.Id)
doc.Regenerate()
else:
continue
self.Refresh()
UpdateSetNames(CurrentSetsListBox)
t.Commit()
I've tried to build a function to restart/refresh the Form but it doesn't work (code below):
global PrintSetForm_Load
def PrintSetForm_Load(self, sender):
Application.Exit()
Application.Restart()
#self.Refresh()
#self.ResetBindings()
#self.ActiveForm.Close()
sd = PrintSetForm()
sd.ShowDialog()
This gif shows the form in action:
Manage Print Sets
Any ideas or suggestions?
Thank you.
3) If I try to populate the SheetsLb with a DataSource, just the first set clicked is shown.
Sheets=[sheet.Name for sheet in view_set.Views]
SheetNumber=[sheet.get_Parameter(BuiltInParameter.SHEET_NUMBER).AsString() for sheet in view_set.Views]
SheetsLb.BeginUpdate()
SheetsLb.DataSource = None
SheetsLb.Items.Clear()
UpdatedList=[]
for number,name in zip(SheetNumber,Sheets):
UpdatedList.append(number+" - "+ name + " [ ] ")
SheetsLb.DataSource=UpdatedList
SheetsLb.EndUpdate()
1) See if this works:
It would be worth checking that there is something selected in self.viewSetsLb. Ive added a check to the code below
The view_set variable could be initialised as a boolean instead of a list
Using break in the for loop keeps things a little snappier
Ive used the more pythonic for view in PrintSetForm.viewSets rather than for i in PrintSetForm.viewSets - keeping it nice and clear
This code works for me:
self.curItem = self.viewSetsLb.SelectedItem
if not self.viewSetsLb.SelectedItem:
print 'No Printset selected!'
return
view_set = False
for view in PrintSetForm.viewSets:
if view.Name == str(self.curItem):
view_set = view
break
else:
continue
Sheets=[sheet.Name for sheet in view_set.Views]
self.sheetsLb.BeginUpdate()
self.sheetsLb.Items.Clear()
for sheet in Sheets:
self.sheetsLb.Items.Add(sheet)
self.sheetsLb.EndUpdate()
2) Its because the data in your PrintSetForm.ViewSets list is out of date. Every time you change something (ie delete a viewset), repopulate this list:
PrintSetForm.ViewSets = FilteredElementCollector(doc).OfClass(ViewSheetSet).ToElements()
Also, you shouldnt need to build a refresh button, perhaps have a class function that repopulates the Printset list and ListBox, and clears the Sheet ListBox that you call after every action?
Sounds like youre having fun mate!
It sounds as if you have an issue with the scoping and lifetime of variables. For instance, some variables may have a lifetime limited to the form display, and therefore cannot be accessed after the form is closed. You could change the lifetime of these variables, e.g., by making them static class variables instead of local instance variables. I suggest you read up on .net static class variable scope.

hexagon buttons in GTK+

I am trying to create a button in GTK+ that has the shape of a Hexagon.
How can I do it without using CSS?
And more general, how can I create my button in any shape I want?
Is it possible to do such things in Glade(User interface edior for GTK+)?
When I put my comment I was bluffing because I never did the circular button.. I just did an example of an Hexagonal button using my original idea.. I got surprised that it was simpler than I thought!
( and by the way, no, it is not possible to do it in glade! )
# sorry but the example is in Python! :/
from gi.repository import Gtk
def hexagon(coord_x, coord_y):
# because of the symetry I take only the absolute value
coord_x, coord_y= abs(coord_x), abs(coord_y)
# I got the constants by clicling in the image and printing the coord_x and coord_y values
if coord_x <= 13 and coord_y <= 25: # define a rectangle
return True
else:
# I cut the coord x to define a triangle
coord_x=coord_x-13/2
# line equation
ymax=(-25/31)*coord_x+25
if coord_y < ymax:
return True
else:
return False
class GUI(Gtk.Window):
def __init__(self):
self.window_root=Gtk.Window()
# Create an event box to handle the click's
self.eventbox=Gtk.EventBox()
self.eventbox.connect('button-press-event' , self.on_eventbox_pressed)
self.eventbox.connect('button-release-event' , self.on_eventbox_released)
# Load the images
self.hexagon1=Gtk.Image.new_from_file('./3uSFN.png')
self.hexagon2=Gtk.Image.new_from_file('./cWmUA.png')
# init the event box
self.eventbox.add(self.hexagon1)
self.window_root.add(self.eventbox)
self.window_root.show_all()
# a variable to store the state of the button
self.state=False
def on_eventbox_pressed(self, widget , event):
if 'GDK_BUTTON_PRESS' in str(event.type): # If the user made a "single click"
if event.button == 1: # if it is a left click
# get the x,y of the mouse from the center of the image
pos_x, pos_y=self.window_root.get_position()
siz_x, siz_y=self.window_root.get_size()
mouse_x,mouse_y=event.x-siz_x/2, siz_y/2-event.y
if hexagon(mouse_x, mouse_y):
self.eventbox.remove(self.hexagon1)
self.eventbox.add(self.hexagon2)
self.eventbox.show_all()
self.state=True
def on_eventbox_released(self, widget , event):
if self.state:
self.eventbox.remove(self.hexagon2)
self.eventbox.add(self.hexagon1)
self.state=False
main=GUI()
Gtk.main()
I think that the only inconvenient of using this to solve your problem is that the theme of the user is not respected. If that is a problem, instead of using an image you could draw your button by using a DrawingArea and by getting the theme colors as I suggested here!
I hope it be useful :)

Resources