I've got some problems with refering from 1 file to another.
I've got 2 VCL Forms:
- OpenPlotFile
- SelectElement
In my Plotfile I've got an openDialog:
void __fastcall TPlotFileForm::btn_fileselectClick(TObject *Sender)
{
AnsiString message;
//Dialog opties instellen
OpenDialog->Options << ofFileMustExist;
OpenDialog->Filter ="PPD files (*.PPD) |*.ppd |PLOT files (PLOT.*) | plot.*";
OpenDialog->FilterIndex = 2;
if (OpenDialog->Execute())
{
plotFile = OpenDialog->FileName;
Itxt_plotfile->Text=plotFile;
try
{
TFileStream *plotStream = new TFileStream(plotFile, fmOpenRead);
TStringStream *plotString = new TStringStream();
plotString->CopyFrom(plotStream, plotStream->Size);
FileBuffer = plotString->DataString;
delete plotStream;
delete plotString;
message = "Make your choice what to plot";
ListBox1->Items->Add(message);
message = "Default is everything, on insulation and with automatic weepholes at 1000 mm...";
ListBox1->Items->Add(message);
message = "Accept with the OK button...";
ListBox1->Items->Add(message);
btn_OK->Enabled=true;//Knop activeren nadat file is gekozen
}
catch(EStreamError &e)
{
ShowMessage(e.Message);
}
}
}
In this file I have a plotFile, this is the file directory. I want to get that value to another form: SelectElement
How I do it now is simple: I add AnsiString plotFile; to the OpenPlotFile.h
And I include OpenPlotFile.h in the SelectElement file.
#include "PlotFileScreen.h"
void __fastcall TSelectElementForm::FormShow(TObject *Sender)
{
element *ElementArray = new element[100];
ElementArray = GetElementInfo();
Itxt_plot_file->Text = plotFile;
Itxt_ordernumber->Text = ElementArray[0].ON;
Itxt_element_id->Text = ElementArray[0].MO;
Itxt_type->Text = ElementArray[0].SN;
Itxt_concrete->Text = ElementArray[0].el_concrete_height;
Itxt_Insulation->Text = ElementArray[0].el_iso_height;
Itxt_Length->Text = ElementArray[0].el_length;
Itxt_Width->Text = ElementArray[0].el_width;
Itxt_Weight->Text = ElementArray[0].el_weight;
Itxt_slabmark->Text = "";
Itxt_reinforce->Text = ElementArray[0].OW;
}
My program compiles and it works fine, but the odd thing is, When I debug, in both files it says: plotFile = NULL.
How can I solve this? Or how can I pass the plotFile to the other file without being NULL?
FYI: Global variables are ugly and should be avoided when possible. Encapsulation and abstraction are your friends. But to answer your question:
If plotFile belongs to your header file by declaring it via AnsiString plotFile; each translation unit gets its own copy. You need to define your variable in one *.cpp file and declare it as extern in your header.
From the C++ Standard:
3.5 Program and linkage
When a name has external linkage , the entity it denotes can be
referred to by names from scopes of other translation units or from
other scopes of the same translation unit.
So in your header file you have to place this:
extern AnsiString plotFile;
Define your variable in one cpp file:
AnsiString plotFile;
Don't use global variables for this, sooner or later you will get into trouble if you will always use this. One problem it causes is that you can use only once instance of your form because it is occupying your global variable.
There is a common solution to your problem that is I suppose identical on all platforms/systems/etc.. You have to pass your variable somehow to the form/dialog/etc class instance you want to show.
It looks like you are using Borland Builder C++, or Embarcadero. Proper way to solve your problem is to add AnsiString plotFile as a member variable of SelectElement form, and set it using accessor methods. Example code for it can be found here:
http://bcbjournal.org/articles/vol2/9810/Sharing_data_and_methods_between_forms.htm
Related
currently I'm trying to set up Sol2, and I was trying to use a lua file which needs to acces another lua file. Example: see below
I have no problems with Sol2 in general, but when I try to use two files together my program stops working. The Lua code should be right(...?, I also tried using 'test2 = a.x.test', and 'require('a')'), so Im guessing I need to change something because of Sol2?
a.lua
--------
local x = {
test = 1
}
b.lua
--------
local a = require 'a'
local options = {
test2 = a.test
}
C++:
sol::state lua;
lua.script_file("b.lua");
int x = lua[b][test2];
Thanks!
Local variables are not seen outside their files. So:
Append this line to a.lua:
return x
Append this line to b.lua:
return options
Now you need to fix the C++ side. Probably something like this, but I don't know Sol:
auto result = lua.script_file("b.lua");
int x = result["test2"];
I'm creating a international program, so I need multiple languages in it. On the first screen I have a button with a flag on it, when clicking that flag, it knows the language and what file he needs to read.
For example: if you click the dutch flag it will read a file with Dutch sentences. It will fill the vector with the sentences, later on I use the vector to set the labels/buttons etc to the right language.
The thing is, im using multiple forms and I want to tell my other forms, the language = DUTCH, set the text in the labels/buttons into Dutch. But I need a global variable to work with that.
So my question is: How can I set a global variable?
I need a string thats just saying: "Dutch" or "English".
And I need a global vector for the lines of the file.
MainScreen.h:
extern std::string Global_Language;
extern std::vector<std::string> Global_VectorLanguage;
MainScreen.cpp:
std::string Global_Language = "English"; // since it's by default English
void __fastcall TMainForm::btnLanguageDutchClick(TObject *Sender)
{
TMainForm::SetLanguage("Dutch", "Nederlands.txt");
}
void __fastcall TMainForm::btnLanguageEnglishClick(TObject *Sender)
{
TMainForm::SetLanguage("English", "English.txt");
}
void TMainForm::SetLanguage(string a_Language, string a_fileName)
{
string line;
ifstream myfile;
Global_VectorLanguage.resize(100);
int Index = 0;
myfile.open(a_fileName.c_str());
if (myfile.is_open())
{
while(getline(myfile, line))
{
Global_VectorLanguage[Index] = line;
Index++;
}
myfile.close();
Global_Language = a_Language;
MainForm->Caption = Global_VectorLanguage[0].c_str();
lblHPI->Caption = Global_VectorLanguage[1].c_str();
lblPhoneNo->Caption = Global_VectorLanguage[2].c_str();
lblEmail->Caption = Global_VectorLanguage[3].c_str();
btnStart->Caption = Global_VectorLanguage[4].c_str();
btnStop->Caption = Global_VectorLanguage[5].c_str();
btnResetEmergency->Caption = Global_VectorLanguage[6].c_str();
gboxLicenseInfo->Caption = Global_VectorLanguage[7].c_str();
lblName->Caption = Global_VectorLanguage[8].c_str();
lblVersion->Caption = Global_VectorLanguage[9].c_str();
}
}
ManualScreen.cpp:
__fastcall TManualForm::TManualForm(TComponent* Owner)
: TForm(Owner)
{
if(Global_Language == "Dutch")
{
//set labels/buttons to Dutch
}
}
(What you are caring about is internationalization & localization and your operating system might have support for that, see e.g. locale(7), setlocale(3), gettext(3) etc... on Linux and with C++11 <locale> standard header)
You might declare a few global variables as extern in some header file and defile it in one source file.
E.g. in your header.h file a declaration:
extern std::string my_global_lang;
and in your localization.cc file a definition:
std::string my_global_lang{"English"};
However you often should prefer declaring a static variable inside some class (so called a class variable).
class MyLocalization {
static std::string global_lang;
/// etc...
};
Then use MyLocalization::global_lang
Having many global variables or static member variables is considered poor style. Generally, a program should have few global variables (less than you have fingers on one hand). You might prefer packing state into explicit instances of some class, perhaps declaring some singleton class ProgramState; and have one instance of it created early in your main; the QApplication class of Qt could inspire you.
I strongly recommend enabling all warnings & debug info when compiling (e.g. g++ -Wall -Wextra -g if using GCC) and reading some good C++ programming book and sites. We cannot teach you the basics of C++ programming (which is difficult) here.
You handle global variables just like you do local variables. The difference is mainly where the variable is declared. Just try something like:
#include <string>
std::string language = "English";
int main(void)
{
...
if (/*user changes language to Dutch*/)
{
if (language == "English")
language = "Dutch";
else
language = "English";
}
...
}
I know that C++ cannot create variables at runtime. Everything has to be declared when it is compiled.
My question is, if I have, let's say, 10 included header files with simple variable names, can I reference them dynamically, by the header file name or something like that.
For example, if I had two header files, one called "myVars1.h" with variable "myVars1name" and another called "myVars2.h" with a variable "myVars2name" could I do something like
int fileNum = 1;
string name = ["myVars" + fileNum + "name]; //i wish this worked...
Is this along the same lines as creating variables at runtime (and therefore illegal)?
Thanks
Assuming these variables are declared in header files, and defined somewhere else as global variables, you may get what you want by using dlsym(). Basically C/C++ cannot define variables at runtime, but it can load them at run time.
Precondition: these variables must be built into shared library, e.g. mylib.so
....
int fileNum = 1;
string name = ["myVars" + fileNum + "name]; //i wish this worked...
void *handle = dlopen("$PATH/mylib.so", RTLD_LAZY);
void *varPtr = dlsym(handle, name); // Your wish comes true here...
//cast varPtr to its target type.
....
I think you should use Namespaces
I'm writing a Cocos2D-X game where the player, enemies and other characters store their attributes in a CCMutableDictionary, which is somewhat of a decorator class for std::map<std::string, CCObject*>. A value in the dictionary can be accessed via the CCMutableDictionary::objectForKey(const std::string& key) method.
Now, in a header file included by many of my .cpp files, I've got a few const char * const strings for accessing values in the dictionaries, like this:
// in Constants.h
const char* const kAttributeX = "x";
const char* const kAttributeY = "y";
// in a .cpp file
CCObject* x = someDictionary->objectForKey(kAttributeX);
So, correct me if I'm wrong, but std::string's copy constructor is being called and a temporary std::string is on the stack every time I call one of the above objectForKey methods using a const char* const, right?
If so, I feel that it would be more efficient at runtime if those constant attribute keys were already std::string objects. But how do I do that the right way?
Defining them in the Constants.h file like the following compiles fine, but I have a feeling that something just isn't right:
// in Constants.h
const std::string kAttributeX = "x";
const std::string kAttributeY = "y";
My apologies if this question has already been asked. I couldn't seem to find the exact answer I was looking for here on StackOverflow.
The code you wrote is perfectly fine, at least as you only #include the Constants.h file in only one source file. If you use the header file in multiple source files, you will have the same variables defined multiple times. The correct use of constants in header files are to split them into a header (Constants.h) which contains the declarations of the variables, and a source file (Constants.cpp) which contains the definitions of the variables:
The header file:
#ifndef CONSTANTS_H
#define CONSTANTS_H
extern const std::string kAttributeX;
extern const std::string kAttributeY;
#endif
The source file:
const std::string kAttributeX = "x";
const std::string kAttributeY = "y";
Your second option causes each of the variables to be created in every translation unit (cpp file that includes the header) which will slightly increase code size as well as adding a bit of runtime cost (constructing all those string during launch and destructing them during process termination).
The solution suggested by Joachim works but I find declaring and defining variables separately to be a bit of a drag. I personally hate repeating myself, also I don't like saying the same thing over and over again...
I don't know of a good solution for this in C++ proper but the compilers I've worked with all support something like __declspec( selectany ) so that you can define the variable in the header file and only get one object instantiated (rather than one for each translation unit).
__declspec( selectany ) extern const std::string kAttributeX = "x";
(For why both extern and const see this answer).
You still have the drawback of paying the initialization price of all the global variables during process launch. This is acceptable 101% of the time (give or take 2%) but you can avoid this by using lazy objects (I've written about something similar here).
I am a newbie in programming and apologise in advance if my question is too silly.
My c++ project is compiled as library .xll (DLL for excel), the framework code (program entry point) is coded correct and work stable. Custom functions are separate modules.
// header.h
typedef struct _TMDYDate {
long month;
long day;
long year;
} TMonthDayYear;
the file funcs.c has a function:
// funcs.c
#include "header.h"
__declspec(dllexport) long GetDate() {
TMonthDayYear myDate;
myDate.day = 1 ;
myDate.month = 1;
myDate.year = 2000;
if (DateToMDY(2004, &myDate) != 1) {
return 0;
}
return myDate.year;
}
where the function DateToMDY is declared in separate file Dates.c:
// dates.c
int DateToMDY (long tmpyear, TMonthDayYear *mdy) {
mdy->year = tmpyear; // <- Error is here
return 1;
}
I debug a function GetDate() and get an error when try to assign by reference (mdy->year = tmpyear;) the value 2004.
The error is:
Unhandled exception at 0x0e342b84 (alcDates.xll) in EXCEL.EXE: 0xC0000005: Access violation writing location 0x40e3db28
The funny thing is when i move declaration of DateToMDY to the file funcs.c, the same where the DateToMDY is called - there is no error.
I assume it is to wrong memory usage, but for me is critical to isolate functionality in different modules (ex. dates.c, array.c, sorting.c ...).
I don't know where to look for, may be i have wrong project compilation settings.
It seems like you call the function from a place where its declaration isn't visible. If you do, the compile does not know what types the parameters should have so it passes them all as ints.
Functions called from another .c file should be declared in the corresponding .h file,and included in all .c files using the function.