英文:
Issue handling TComponent objects (TEdits, TLabels, ...) from a TForm object, saved in an unordered_map (member of my own class)
问题
我正在尝试从保存在std::unordered_map中的TForm对象中处理TComponent对象(例如TEdit、TLabel等)。但是当我尝试处理它们时,一些奇怪的事情发生了。
Test.h
//---------------------------------------------------------------------------
#ifndef TestH
#define TestH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include "Container.h"
#include "Handler.h"
//---------------------------------------------------------------------------
class TUMap_Test : public TForm
{
__published: // IDE-managed Components
TEdit *Edit1;
TEdit *Edit2;
TEdit *Edit3;
TEdit *Edit4;
TLabel *Label1;
TLabel *Label2;
TLabel *Label3;
TLabel *Label4;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
Container Cont;
public: // User declarations
__fastcall TUMap_Test(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TUMap_Test *UMap_Test;
//---------------------------------------------------------------------------
#endif
我创建了一个名为Container的类来打包这些TComponent对象,如下所示:
Container.h
#ifndef CONTAINERH
#define CONTAINERH
#include <vcl.h>
#include <unordered_map>
#include <map>
class Container{
private:
TForm * m_Form;
std::unordered_map<String, TEdit*> m_Edits;
std::unordered_map<String, TLabel*> m_Labels;
void packEdits();
void packLabels();
public:
Container(){}
void packComponents(TForm * Form);
std::unordered_map<String, TEdit*> * getEdits();
std::unordered_map<String, TLabel*> * getLabels();
};
#endif
Container.cpp
#include "Container.h"
void Container::packComponents(TForm * Form){
m_Form = Form;
packEdits();
packLabels();
}
void Container::packEdits(){
String Edits[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; i++) {
m_Edits.insert(std::make_pair(Edits[i], dynamic_cast<TEdit*>(m_Form->FindComponent(Edits[i]))));
}
}
void Container::packLabels(){
String Labels[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; i++) {
m_Labels.insert(std::make_pair(Labels[i], dynamic_cast<TLabel*>(m_Form->FindComponent(Labels[i]))));
}
}
std::unordered_map<String, TEdit*> * Container::getEdits(){
return &m_Edits;
}
std::unordered_map<String, TLabel*> * Container::getLabels(){
return &m_Labels;
}
然后,我在我的TForm对象中创建了一个名为Cont的Container对象。为了以后打包这些TComponent对象,我必须使用TForm对象作为packComponents()方法的参数(packComponents(TForm * Form))。然后,我使用Form->FindComponent()将我的组件插入std::unordered_map。
我创建了一个处理我的打包在std::unordered_map中的TComponent对象的处理函数:
Handler.h
#pragma once
#include "Container.h"
#include <vcl.h>
void TextEditsToLabels(Container * Cont);
Handler.cpp
#include "Handler.h"
void TextEditsToLabels(Container * Cont){
//将标签的标题更改为编辑框的文本
(*Cont->getLabels())["Label1"]->Caption = (*Cont->getEdits())["Edit1"]->Text;
(*Cont->getLabels())["Label2"]->Caption = (*Cont->getEdits())["Edit2"]->Text;
(*Cont->getLabels())["Label3"]->Caption = (*Cont->getEdits())["Edit3"]->Text;
(*Cont->getLabels())["Label4"]->Caption = (*Cont->getEdits())["Edit4"]->Text;
}
最后,在Test.cpp中,我调用了Cont的packer()函数,然后在Button1上创建了一个事件函数来调用TextEditsToLabels()函数。
Test.cpp
#include <vcl.h>
#pragma hdrstop
#include "Test.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TUMap_Test *UMap_Test;
fastcall TUMap_Test::TUMap_Test(TComponent* Owner): TForm(Owner){
Cont.packComponents(this);
}
void __fastcall TUMap_Test::Button1Click(TObject *Sender){
TextEditsToLabels(&Cont);
}
问题是,当我点击Button1时,什么都没有发生。所以我在TextEditsToLabels()函数中设置了断点,以查看发生了什么,并创建了四个变量来获取这些TEdit的Text。这些新变量显示了NULL值。
#include "Handler.h"
void TextEditsToLabels(Container * Cont){
String Text1 = (*Cont->getEdits())["Edit1"]->Text;
String Text2 = (*Cont->getEdits())["Edit2"]->Text;
String Text3 = (*Cont->getEdits())["Edit3"]->Text;
String Text4 = (*Cont->getEdits())["Edit4"]->Text;
//BREAKPOINT
//将标签的标题更改为编辑框的文本
//(*Cont->getLabels())["Label1"]->Caption = (*Cont->getEdits())["Edit1"]->Text;
//(*Cont->getLabels())["Label2"]->Caption = (*Cont->getEdits())["Edit2"]->Text;
//(*Cont->getLabels())["Label3"]->Caption = (*Cont->getEdits())["Edit3"]->Text;
//(*Cont->getLabels())["Label4"]->Caption = (*Cont->getEdits())["Edit4"]->Text;
}
注意:在点击Button1之前,我在我的TEdit中放入了一些随机值,期望在我的四个新变量中看到它们。
我尝试将容器类型从std::unordered_map更改为std::map,然后问题部分解决了:
std::map<String, TEdit*> m_Edits;
我说部分解决了,因为我需要使用std::unordered_map以获得更好的性能,因为我以后会打包大量TComponent,如果使用std::map,性能将更差。
英文:
I'm trying to handle TComponent
objects (TEdit
, TLabel
, ...) from my TForm
object which are saved in an std::unordered_map
. But something weird happens to the pair values when I try to handle them.
Test.h
//---------------------------------------------------------------------------
#ifndef TestH
#define TestH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include "Container.h"
#include "Handler.h"
//---------------------------------------------------------------------------
class TUMap_Test : public TForm
{
__published: // IDE-managed Components
TEdit *Edit1;
TEdit *Edit2;
TEdit *Edit3;
TEdit *Edit4;
TLabel *Label1;
TLabel *Label2;
TLabel *Label3;
TLabel *Label4;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
Container Cont;
public: // User declarations
__fastcall TUMap_Test(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TUMap_Test *UMap_Test;
//---------------------------------------------------------------------------
#endif
I made a Container
class to pack those TComponent
objects as follows:
Container.h
#ifndef CONTAINERH
#define CONTAINERH
#include <vcl.h>
#include <unordered_map>
#include <map>
class Container{
private:
TForm * m_Form;
std::unordered_map<String, TEdit*> m_Edits;
std::unordered_map<String, TLabel*> m_Labels;
void packEdits();
void packLabels();
public:
Container(){}
void packComponents(TForm * Form);
std::unordered_map<String, TEdit*> * getEdits();
std::unordered_map<String, TLabel*> * getLabels();
};
#endif
Container.cpp
#include "Container.h"
void Container::packComponents(TForm * Form){
m_Form = Form;
packEdits();
packLabels();
}
void Container::packEdits(){
String Edits[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; i++) {
m_Edits.insert(std::make_pair(Edits[i], dynamic_cast<TEdit*>(m_Form->FindComponent(Edits[i]))));
}
}
void Container:: packLabels(){
String Labels[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; i++) {
m_Labels.insert(std::make_pair(Labels[i], dynamic_cast<TLabel*>(m_Form->FindComponent(Labels[i]))));
}
}
std::unordered_map<String, TEdit*> * Container::getEdits(){
return &m_Edits;
}
std::unordered_map<String, TLabel*> * Container::getLabels(){
return &m_Labels;
}
Then I create a Container
object named Cont
in my TForm
object. In order to pack those TComponent
objects later, I had to use the TForm
object as an argument of the packComponents()
method (packComponents(TForm * Form)
). Then I used Form->FindComponent()
to insert my components into a std::unordered_map
.
I made a handler function to handle my TComponent
objects that are packed in a std::unordered_map
:
Handler.h
#pragma once
#include "Container.h"
#include <vcl.h>
void TextEditsToLabels(Container * Cont);
Handler.cpp
#include "Handler.h"
void TextEditsToLabels(Container * Cont){
//Change the Caption of Labels to Edits Text
(*Cont->getLabels())["Label1"]->Caption = (*Cont->getEdits())["Edit1"]->Text;
(*Cont->getLabels())["Label2"]->Caption = (*Cont->getEdits())["Edit2"]->Text;
(*Cont->getLabels())["Label3"]->Caption = (*Cont->getEdits())["Edit3"]->Text;
(*Cont->getLabels())["Label4"]->Caption = (*Cont->getEdits())["Edit4"]->Text;
}
Finally, in Test.cpp
, I called the packer()
function of my Container
object, and then I made an event function on Button1
to call the TextEditsToLabels()
function.
Test.cpp
#include <vcl.h>
#pragma hdrstop
#include "Test.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TUMap_Test *UMap_Test;
fastcall TUMap_Test::TUMap_Test(TComponent* Owner): TForm(Owner){
Cont.packComponents(this);
}
void __fastcall TUMap_Test::Button1Click(TObject *Sender){
TextEditsToLabels(&Cont);
}
The problem is, when I click on Button1
, nothing happens. So I put a breakpoint in my TextEditsToLabels()
function to see what is happening, and made four variables to get the Text
inside of those TEdit
s. Those new variables show me NULL values:
#include "Handler.h"
void TextEditsToLabels(Container * Cont){
String Text1 = (*Cont->getEdits())["Edit1"]->Text;
String Text2 = (*Cont->getEdits())["Edit2"]->Text;
String Text3 = (*Cont->getEdits())["Edit3"]->Text;
String Text4 = (*Cont->getEdits())["Edit4"]->Text;
//BREAKPOINT
//Change the Caption of Labels to Edits Text
//(*Cont->getLabels())["Label1"]->Caption = (*Cont->getEdits())["Edit1"]->Text;
//(*Cont->getLabels())["Label2"]->Caption = (*Cont->getEdits())["Edit2"]->Text;
//(*Cont->getLabels())["Label3"]->Caption = (*Cont->getEdits())["Edit3"]->Text;
//(*Cont->getLabels())["Label4"]->Caption = (*Cont->getEdits())["Edit4"]->Text;
}
Note: Before clicking on Button1
, I put some random values in my TEdit
, expecting to see them in my four new variables:
I tried to change the container type from std::unordered_map
to std::map
, and then the problem was partially solved:
std::map<String, TEdit*> m_Edits;
I say partially solved because I need to use std::unordered_map
to have better performance, as I will pack lots of TComponent
s later, so it will perform worst if I use std::map
.
答案1
得分: 1
packLabels()
正在搜索 TEdit
对象而不是 TLabel
对象,并将它们转换为 TLabel
,这将会失败,但您没有检查这种情况,因此您的 m_Labels
映射最终会填充为 NULL
指针。
因此,TextEditsToLabels()
展示了未定义行为,因为它试图访问 m_Labels
映射中不存在的 TLabel
对象,但您没有检查这种情况。如果指定的键不存在,映射的 operator[]
将返回一个 NULL 指针。切换到 std::map
并不能“部分解决”这个问题。
您需要修复 packLabels()
中的错误,然后您显示的代码的其余部分 应该 工作正常,例如:
void Container::packLabels(){
//String Labels[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
String Labels[4] = {"Label1", "Label2", "Label3", "Label4"}; // <-- 这里
for (int i = 0; i < 4; i++) {
m_Labels.insert(std::make_pair(Labels[i], dynamic_cast<TLabel*>(m_Form->FindComponent(Labels[i]))));
}
}
您还没有检查 FindComponent()
在插入映射之前是否返回了一个 NULL 指针。您也应该修复这个问题,例如:
void Container::packEdits(){
String Edits[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; i++) {
TComponent* comp = m_Form->FindComponent(Edits[i]);
if (comp) {
m_Edits.insert(std::make_pair(Edits[i], static_cast<TEdit*>(comp)));
}
}
}
void Container::packLabels(){
String Labels[4] = {"Label1", "Label2", "Label3", "Label4"};
for (int i = 0; i < 4; i++) {
TComponent* comp = m_Form->FindComponent(Labels[i]);
if (comp) {
m_Labels.insert(std::make_pair(Labels[i], static_cast<TLabel*>(comp)));
}
}
}
另外:您的代码在一些地方使用了指针,实际上应该使用引用。
我建议将代码更改为以下方式:
Test.h:
// 这部分不是翻译,是代码,请忽略
Test.cpp:
// 这部分不是翻译,是代码,请忽略
Container.h:
// 这部分不是翻译,是代码,请忽略
Container.cpp:
// 这部分不是翻译,是代码,请忽略
Handler.h:
// 这部分不是翻译,是代码,请忽略
Handler.cpp:
// 这部分不是翻译,是代码,请忽略
如果您有任何其他疑问,请随时提出。
英文:
packLabels()
is searching for TEdit
objects instead of TLabel
objects, and is dynamic_cast
'ing them to TLabel
, which will fail but you are not checking for that condition, and so your m_Labels
map ends up being filled with NULL
pointers.
As such, TextEditsToLabels()
exhibits undefined behavior because it is trying to access TLabel
objects that do not exist in the m_Labels
map, but you are not checking for that condition. The map's operator[]
will return a NULL pointer if the specified key does not exist. Switching to std::map
does not "partially solve" that problem.
You need to fix that packLabels()
error, then the rest of the code you have shown should work fine, eg:
void Container:: packLabels(){
//String Labels[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
String Labels[4] = {"Label1", "Label2", "Label3", "Label4"}; // <-- HERE
for (int i = 0; i < 4; i++) {
m_Labels.insert(std::make_pair(Labels[i], dynamic_cast<TLabel*>(m_Form->FindComponent(Labels[i]))));
}
}
You are also not checking whether FindComponent()
is returning a NULL pointer before inserting into your maps. You should fix that as well, eg:
void Container::packEdits(){
String Edits[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; i++) {
TComponent* comp = m_Form->FindComponent(Edits[i]);
if (comp) {
m_Edits.insert(std::make_pair(Edits[i], static_cast<TEdit*>(comp)));
}
}
}
void Container:: packLabels(){
String Labels[4] = {"Label1", "Label2", "Label3", "Label4"};
for (int i = 0; i < 4; i++) {
TComponent* comp = m_Form->FindComponent(Labels[i]);
if (comp) {
m_Labels.insert(std::make_pair(Labels[i], static_cast<TLabel*>(comp)));
}
}
}
On a side note: your code is using pointers in places that really should be using references instead.
I would suggest changing the code to be more like the following instead:
Test.h
//---------------------------------------------------------------------------
#ifndef TestH
#define TestH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include "Container.h"
//---------------------------------------------------------------------------
class TUMap_Test : public TForm
{
__published: // IDE-managed Components
TEdit *Edit1;
TEdit *Edit2;
TEdit *Edit3;
TEdit *Edit4;
TLabel *Label1;
TLabel *Label2;
TLabel *Label3;
TLabel *Label4;
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
Container Cont;
public: // User declarations
__fastcall TUMap_Test(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TUMap_Test *UMap_Test;
//---------------------------------------------------------------------------
#endif
Test.cpp
#include <vcl.h>
#pragma hdrstop
#include "Test.h"
#include "Handler.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TUMap_Test *UMap_Test;
fastcall TUMap_Test::TUMap_Test(TComponent* Owner): TForm(Owner), Cont(this) {
Cont.packComponents();
}
void __fastcall TUMap_Test::Button1Click(TObject *Sender){
TextEditsToLabels(Cont);
}
Container.h
#ifndef ContainerH
#define ContainerH
#include <vcl.h>
#include <unordered_map>
class Container{
private:
TForm* m_Form;
std::unordered_map<String, TEdit*> m_Edits;
std::unordered_map<String, TLabel*> m_Labels;
void packEdits();
void packLabels();
public:
Container(TForm* Form);
void packComponents();
std::unordered_map<String, TEdit*>& getEdits();
std::unordered_map<String, TLabel*>& getLabels();
/* alternatively:
TEdit* getEdit(String Name);
TLabel* getLabel(String Name);
*/
};
#endif
Container.cpp
#include "Container.h"
Container::Container(TForm* Form) {
m_Form = Form;
}
void Container::packComponents() {
packEdits();
packLabels();
}
void Container::packEdits() {
String Edits[4] = {"Edit1", "Edit2", "Edit3", "Edit4"};
for (int i = 0; i < 4; ++i) {
TComponent *comp = m_Form->FindComponent(Edits[i]);
TEdit *edit = dynamic_cast<TEdit*>(comp);
if (edit) {
m_Edits[Edits[i]] = edit;
}
}
}
void Container::packLabels() {
String Labels[4] = {"Label1", "Label2", "Label3", "Label4"};
for (int i = 0; i < 4; ++i) {
TComponent* comp = m_Form->FindComponent(Labels[i]);
TLabel *label = dynamic_cast<TLabel*>(comp);
if (label) {
m_Labels[Labels[i]] = label;
}
}
}
std::unordered_map<String, TEdit*>& Container::getEdits() {
return m_Edits;
}
std::unordered_map<String, TLabel*>& Container::getLabels() {
return m_Labels;
}
/* alternatively:
TEdit* Container::getEdit(String Name) {
return m_Edits.at(Name);
}
TLabel* Container::getLabel(String Name) {
return m_Labels.at(Name);
}
*/
Handler.h
#ifndef HandlerH
#define HandlerH
#include "Container.h"
void TextEditsToLabels(Container& Cont);
#endif
Handler.cpp
#include "Handler.h"
static String getEditText(TEdit* edit) {
if (edit) {
return edit->Text;
}
return EmptyStr;
}
static void TextEditToLabel(TEdit* edit, TLabel* label) {
if ((edit) && (label)) {
label->Caption = edit->Text;
}
}
void TextEditsToLabels(Container& Cont) {
std::unordered_map<String, TEdit*>& edits = Cont.getEdits();
std::unordered_map<String, TLabel*>& labels = Cont.getLabels();
String Text1 = getEditText(edits["Edit1"]);
String Text2 = getEditText(edits["Edit2"]);
String Text3 = getEditText(edits["Edit3"]);
String Text4 = getEditText(edits["Edit4"]);
//BREAKPOINT
//Change the Caption of Labels to Edits Text
TextEditToLabel(edits["Edit1"], labels["Label1"]);
TextEditToLabel(edits["Edit2"], labels["Label2"]);
TextEditToLabel(edits["Edit3"], labels["Label3"]);
TextEditToLabel(edits["Edit4"], labels["Label4"]);
/* alternatively:
String Text1 = Cont.getEdit("Edit1")->Text;
String Text2 = Cont.getEdit("Edit2")->Text;
String Text3 = Cont.getEdit("Edit3")->Text;
String Text4 = Cont.getEdit("Edit4")->Text;
//BREAKPOINT
//Change the Caption of Labels to Edits Text
Cont.getLabel("Label1")->Caption = Cont.getEdit("Edit1")->Text;
Cont.getLabel("Label2")->Caption = Cont.getEdit("Edit2")->Text;
Cont.getLabel("Label3")->Caption = Cont.getEdit("Edit3")->Text;
Cont.getLabel("Label4")->Caption = Cont.getEdit("Edit4")->Text;
*/
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论