I have an application, in which I have added a QTabWidget.
Tabs are closable.
When I add new tab, if the tab is already added, it still add new tab and make duplicate.
I want to avoid this duplication.
If the tab is opened already then It just active that tab and not open again.
You help will be appreciated.
Thanks
To add on top of Prakash's answer, be aware that some times the tab title is not a good identifier of the content of the tab (this of course depends on the situation). For example, you might have a file manager where the current directory is the title of the tab, but there might be different directories with the same name across your filesystem.
I would follow the following strategy for identifying tab contents: Qt allows you to set dynamical properties to widgets (see QObject::setProperty), so each time you create a new tab, for example of a file manager, you might do something like
widget = ...
widget->setProperty("tab_dir_fullpath", the_full_path);
tabWidget->addWidget(widget, directory_name);
where the_full_path would be a unique identifier (in this example, the full absolute path to the current directory), which will not be displayed to the user but which you can later use to see if a given directory is already open.
Then, when opening a new tab, you should check whether the same full path is already open:
for (int k = 0; k < tabWidget->count(); ++k) {
if (tabWidget->widget(k)->property("tab_dir_fullpath").toString() == the_full_path_to_open) {
tabWidget->setCurrentIndex(k);
return;
}
}
... // open new tab, as in the previous snippet.
Use tabText(int index) to get the identifier of the each tab before adding a new tab addTab(QWidget * page, const QString & label) and compare the label texts, if already exist just setCurrentIndex of that index or else add a new tab.
Inspired by Noor Nawaz's comment, my approch is:
void MainWindow::openPanel1()
{
for(int i=0;i<ui->tabWidget->count();i++) {
if(ui->tabWidget->tabText(i) == "Panel1") {
ui->tabWidget->setCurrentIndex(i);
return;
}
}
Panel1 = new panel1Widget();
int index = ui->tabWidget->addTab(Panel1,"Panel1");
ui->tabWidget->setCurrentIndex(index);
}
Also its very good to use setTabData() instead of property which is more proper way of doing.
Related
I have a simple JavaFX app that allows the user to query a database and see the data in a table.
I'd like to allow the user to be able to click a table cell and copy text from that cell to the clipboard with the standard clipboard key stroke: ctrl-c for Win/Linux or cmd-c for Mac. FYI, the text entry controls support basic copy/paste by default.
I'm using the standard javafx.scene.control.TableView class. Is there a simple way to enable cell copy? I did some searches and I see other people create custom menu commands... I don't want to create a custom menu, I just want basic keyboard copy to work with single cells.
I'm using single selection mode, but I can change to something else if need be:
TableView<Document> tableView = new TableView<Document>();
tableView.getSelectionModel().setCellSelectionEnabled(true);
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
You just have to create a listener in the scene, something like:
scene.getAccelerators()
.put(new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_ANY), new Runnable() {
#Override
public void run() {
int row = table.getSelectionModel().getSelectedIndex();
DataRow tmp = table.getItems().get(row);
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent content = new ClipboardContent();
if(table.getSelectionModel().isSelected(row, numColumn)){
System.out.println(tmp.getNumSlices());
content.putString(tmp.getNumSlices().toString());
}
else{
System.out.println(tmp.getSelected());
content.putString(tmp.getSelected());
}
clipboard.setContent(content);
}
});
For a complete example, you can download it at the gist.
I recommended that you review this post, work for me
http://respostas.guj.com.br/47439-habilitar-copypaste-tableview-funcionando-duvida-editar-funcionalidade
The author use an aditional util java class for enable the cell content copy from a tableView
Im a student developer using Qt to build a GUI to help users plot specific columns of data located in multiple files. The feature I'm setting up allows users to select a file using a button in each row. So the button originally would say browse and then user clicks it to open a dialog to select a file then the button text is replaced with the file name selected. Sorry for the story; my simple attempt to add some clarity.
The problem I'm having is I'm not sure how to set a policy up for the button clicked. I'd imagine that I'd have to extend the functionality of each of the QPushButtons but I don't really know how to do that. So far I am using the following to set the cell widget.
//with row count set dimensions are set becasue column count is static
//begin bulding custom widgets/QTableWidgetItems into cells
for(int x = 0; x < ui->tableWidgetPlotLineList->rowCount(); x++)
{
for(int y = 0; y < ui->tableWidgetPlotLineList->columnCount(); y++)
{
if(y == 1)
{
//install button widget for file selection
QPushButton *fileButton = new QPushButton();
if(setDataStruct.plotLineListData.at(rowCount).lineFileName != "");
{
fileButton->setText(setDataStruct.plotLineListData.at(rowCount).lineFileName);
}
else
{
fileButton->setText("Browse...");
}
ui->tableWidgetPlotLineList->setCellWidget(x, y, fileButton);
}
I was thinking that
connect(ui->tableWidgetPlotLineList->row(x), SIGNAL(fileButton->clicked()), this, SLOT(selectPlotLineFile(x));
might do the trick but I think I'm probably going in the wrong direction here. Honestly I'm not even too sure as to where it would go...
Thanks so much for reading my post. Please let me know if there is anything lacking from this post and I will update it immediately. I'd also like to thank any contributions to this post in advance!
connect(ui->tableWidgetPlotLineList->row(x), SIGNAL(fileButton->clicked()), this, SLOT(selectPlotLineFile(x));
Is not syntactically correct for a signal/slot connection. Something like this would be more appropriate:
connect(fileButton, SIGNAL(clicked()), this, SLOT(selectPlotLineFile(x));
...
If you need access to the specific button that emited the clicked() signal than you could use the sender() function in your slot:
void selectPlotLineFile() {
QPushButton *button = dynamic_cast<QPushButton*>( sender() )
}
Now you may be wondering how you know which row to operate on. There are several different approaches, one of the easier ones being to maintain a QMap<QPushButton*, int> member variable that you can use to lookup which button belongs to which row.
I create a menu dynamically. I add several checkable actions into one menu. Sometimes actions may have the same text that user sees. It's up to user (actually user adds commands into menu).
The problem is in this case clicking works wrong. If I click on the first action (from 2 with the same texts) everything is good but if I click on the second one, both actions are selected. I don't understand why. The code where actions have been created is here:
for (int i = 0; i< currentList.size(); i++)
{
QString lanKey = currentList.at(i)->Language->toString();
QAction* lanAction = new QAction(this);
QString name ="action_" + currentList.at(i)->Id->toString();
lanAction->setObjectName(name);
lanAction->setText(lanKey);
lanAction->setCheckable(true);
lanAction->setData(i);
connect(lanAction, SIGNAL(triggered(bool)), this, SLOT(ShowSomething(bool)));
ui->menuMy->addAction(lanAction);
}
Here, lanKey is language that may be the same for different actions. Anyway click on the specific action should lead only to checking of this action. What's wrong?
The slot is here:
void VMainWindow::ShowSomething(bool IsTriggered)
{
QAction* senderAction = (QAction*)sender();
int listIndex = senderAction->data().toInt();
if (IsTriggered)
{
CreateEditor(subtitles, listIndex);
}
else
{
//hide this editor
QString name = "editor" + editorsList->Id->toString();
QDockWidget* editorDock = this->findChild<QDockWidget*>(name);
if (editorDock != 0)
{
this->removeDockWidget(editorDock);
this->setLayout(layout());
}
}
}
Thanks
The source of problem is found: it turned out that the slot finds the checked action wrong - by text, not by id.
I can't find a logical issue in the code you posted so far. Here are a couple of options which I would try in order to resolve this problem:
Limit the users possibilities when adding items to a menu so that he can't add two items with the same name.
Add qDebug() output to ShowSomething to see if there is a problem with signals&slots. For example, if the slot gets called once for the first item but twice for the second item there is a problem there.
Debug into CreateEditor step-by-step.
As the problem seems to appear only for actions with a similar name, you should make sure that you never make a lookup of an action (or something related) by its text() but rather by its data() or objectName() (assuming that currentList.at(i)->Id will always be unique)
I made a basic text editor that lets users insert predefined strings into the document with button clicks. What I need to do now is let the user define their own buttons and string values.
For example I have a button that inserts "Hello" into the text. The user may want to create a button that adds "Goodbye".
To accomplish this I figured I would create a .txt file called buttons.txt or something. i would readutfbytee, loop through it to create the buttons. problem is I know what I want to do but not sure where to start. Can someone give me a kick start?
Please check the following code as the simple way to externalize your button settings:
/*
buttons.txt content sample:
Helo=Hello World&Test=Test Inserted
*/
protected function loadSettings():void
{
var varLoader:URLLoader = new URLLoader();
varLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
varLoader.addEventListener(Event.COMPLETE, onSettingsLoaded);
varLoader.load(new URLRequest("data/buttons.txt"));
}
protected function onSettingsLoaded(event:Event):void
{
var varLoader:URLLoader = URLLoader(event.target);
var varButtons:URLVariables = varLoader.data;
var buttons:Dictionary = new Dictionary();
for(var label:String in varButtons{
buttons[label]=varButtons[label].toString().split(",");
}
//use parsed buttons dictionary
}
For starters you need to decide how you are going to store that data that the user enters.
A flex web app can't save any files to the server, so if you want to save this across multiple computers, you'll need a server to do the data saving / retrieval.
If you want to store the buttons just temporarily, and unique to one computer, you can stuff them into a SharedObject.
After you decide this, then you can get more specific on a question of how to do exactly what you're wanting.
This is in reference to yesterday's question "How do I create folders in ASP.NET in code behind". The problem is that I want to create dynamic folders at run time. Folder names will be entered via a TextBox and output will be displayed in a TreeView. The form will submit if I enter the first folder name into textbox1 and click the "Add Folder" button. When I submit multiple folders with the same name, the output should be an indexed increment of the name (e.g., FooFolder, FooFolder(2), FooFolder(3), etc). There are two events: Add Folder Event and Remove Folder Event. If I select a particular child folder and click on the "Remove folder" button, the folder will be removed. For adding a folder I have written the following code:
TreeNode tnode = new TreeNode();
if (TreeView1.Nodes.Count > 0)
{
int found = 0;
for (int i = 0; i < TreeView1.Nodes.Count; i++)
{
if (TreeView1.Nodes[i].Text == TextBox1.Text)
found += 1+i;
}
if (found > 0)
{
tnode.Text = TextBox1.Text + found.ToString();
}
else
{
tnode.Text = TextBox1.Text;
}
}
else
{
tnode.Text = TextBox1.Text;
}
TreeView1.Nodes.Add(tnode);
}
In my code, the ChildNode index is not incrementing; it is always 1, like this:
Sumit
Sumit(1)
Sumit(1)
Sumit(1)
Amit
Amit(5)
Amit(5)
Amit(5)
In the treeview, I have set ImageSet="XPFileExplorer". So the output should look like this:
-Root
-Sumit(Parent1)
NewFolder
NewFolder(2)
NewFolder(3)
NewFolder(4)
NewFolder(5)
-Amit(Parent2)
FooFolder
FooFolder(2)
FooFolder(3)
FooFolder(4)
FooFolder(5)
If I delete any child folder, say, Newfolder(3) and Newfolder(4) and create these same folders under the same Sumit(Parent1), the index should be Newfolder(3),Newfolder(4). If I create one more NewFolder under Sumit with same name then the index should be NewFolder(6).
Could somebody please modify my code to get this desired output?
Your issue here is your algorithim to detect if the item exists. Basically your code:
for (int i = 0; i < TreeView1.Nodes.Count; i++)
{
if (TreeView1.Nodes[i].Text == TextBox1.Text)
found += 1+i;
}
if (found > 0)
{
tnode.Text = TextBox1.Text + found.ToString();
}
else
{
tnode.Text = TextBox1.Text;
}
Let's walk through this. The user submits NewFolder your code goes through and doesn't find any node called NewFolder, so it sets the node to NewFolder.
Now the user clicks add again for NewFolder, this time it finds NewFolder so the new name becomes NewFolder1.
Now the user clicks add again for NewFolder, this time it finds NewFolder so the new name becomes NewFolder1.
Your comparing if TreeView1.Nodes[i].Text == TextBox1.Text, which only one node will ever have this name. You will need to strip off the numeric portion of the name.
If your using a naming convention like NewFolder(1) then you can easily do this. But based on the code you have there the name of the node would be NewFolder1
Before you do this, I learned the hard way that you should not create/remove folders under a running application, or you will cause your app pool to recycle. So make sure that you are creating directories somewhere else on the server. (Hopefully you have that access)
Your text comparison is off. Since you may have added numbers to previous nodes under the same parent, you will only encounter the new name once.
It should look like:
if (TreeView1.Nodes[i].Text.StartsWith(TextBox1.Text))
found++