activex 如何调用OnDraw函数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了activex 如何调用OnDraw函数相关的知识,希望对你有一定的参考价值。
在最初显示或重新绘制 ActiveX 控件时,控件遵循与使用 MFC 开发的其他应用程序相似的过程,但有一个重要的区别:ActiveX 控件可以是活动状态或非活动状态。活动控件在 ActiveX 控件容器中由子窗口表示。与其他窗口一样,活动控件负责在接收到 WM_PAINT 消息时绘制自身。控件的基类 COleControl 在其 OnPaint 函数中处理此消息。此默认实现调用控件的 OnDraw 函数。
非活动控件的绘制过程与此不同。当控件处于非活动状态时,其窗口不可见或不存在,因此无法接收绘制消息。相反,控件容器直接调用控件的 OnDraw 函数。此过程与活动控件的绘制过程不同,因为从不调用 OnPaint 成员函数。
如以上段落所讨论的,如何更新 ActiveX 控件取决于控件的状态。但是,由于框架在两种情况中都调用 OnDraw 成员函数,因此在此成员函数中添加大部分绘制代码。
OnDraw 成员函数处理控件的绘制。当控件处于非活动状态时,控件容器调用 OnDraw,并传递控件容器的设备上下文和该控件所占据的矩形区域的坐标。
框架传递给 OnDraw 成员函数的矩形包含控件占据的区域。如果控件处于活动状态,则左上角是 (0, 0),并且传递的设备上下文是包含该控件的子窗口的设备上下文。如果控件处于非活动状态,则左上角的坐标不一定是 (0, 0),并且传递的设备上下文是包含该控件的控件容器的设备上下文。
其余请见参考资料部分。
下面是咱自己的心得:就像大多数GUI一样,当图形需要初始化时,OnDraw函数响应ONPAINT消息,工程起初生成的三大基类之中的COleControl调用OnPaint方法,OnPaint方法调用OnDraw函数执行绘制;如果控件已被初始化且重新回到活动状态时(重绘),就直接调OnDraw方法。
参考资料:http://msdn.microsoft.com/zh-cn/library/cc451433(v=vs.71).aspx
参考技术A 写好OnDraw();在OnInititalUpdate()里面调用就好啦
onDraw 函数被调用两次?
【中文标题】onDraw 函数被调用两次?【英文标题】:onDraw function gets called twice? 【发布时间】:2020-01-04 01:28:02 【问题描述】:我很难找到这里的错误。我有一个 AlertDialog.Builder 启动了一个自定义对话框,我应该在其中使用 arcDraw 和 Canvas 绘制一个 PieChart,问题是如果我使用调试器使用该应用程序,我可以看到我的图表第一次绘制正确,然后第二次调用进入并且把一切都搞砸了,我不知道它是从哪里来的,需要帮助,一些想法吗?
代码:
package com.example.proiect_stroescumarius.ui;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RatingBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import com.example.proiect_stroescumarius.OnDataPassListener;
import com.example.proiect_stroescumarius.R;
import com.example.proiect_stroescumarius.data.RoomDbInstance;
import com.example.proiect_stroescumarius.data.SharedPrefs;
import com.example.proiect_stroescumarius.data.User;
import java.util.ArrayList;
import java.util.List;
public class ListUsersFragment extends Fragment
private RatingBar ratingBar;
private TextView tv;
private TextView ipPrimit;
private ListView listView;
private RoomDbInstance roomDbInstance;
private OnDataPassListener listener;
private UserListAdapter userListAdapter;
private Button pieChartBtn;
private ListUsersFragment fragment = this;
private int nrRecords = 0;
private List<User> users;
private ArrayList<User> arrayList = new ArrayList<>();
boolean ponderiCalculate = false;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState)
View root = inflater.inflate(R.layout.fragment_listsearch, container, false);
roomDbInstance = RoomDbInstance.getInstance(getContext());
listView = root.findViewById(R.id.list_users);
userListAdapter = new UserListAdapter(root.getContext(), R.layout.customadapter, arrayList);
SharedPrefs sharedPrefs = new SharedPrefs(root.getContext());
ratingBar = root.findViewById(R.id.ratingBar);
tv = root.findViewById(R.id.ratingTV);
ConstraintLayout layout = root.findViewById(R.id.layoutList);
listener.convertFont(sharedPrefs.getFont(), this, layout);
pieChartBtn = root.findViewById(R.id.pieChartBtn);
populateAdapter();
displayRating();
updateListView();
pieChartBtn.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMessage("No entries so can't create any charts...");
builder.setCancelable(true).setPositiveButton("OK", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
AlertDialog builder2 = builder.create();
builder2.dismiss();
).create();
if (nrRecords == 0) builder.show();
else
AlertDialog.Builder builder1 = new AlertDialog.Builder(getActivity());
// LayoutInflater inflater = getLayoutInflater();
View v1 = inflater.inflate(R.layout.pie_chart,null);
RelativeLayout layout = v1.findViewById(R.id.layoutPieChart);
PieInfo pieInfo = calculPonderi();
builder1.setView(v1).show();
float[] deCalculat = new float[pieInfo.pondereCountries.size()];
Toast.makeText(getContext(), String.valueOf(deCalculat[0]), Toast.LENGTH_SHORT).show();
int index = 0;
for (Float f : pieInfo.pondereCountries)
deCalculat[index++] = f;
// Log.d("pie",String.valueOf(deCalculat.length));
// layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
float[] temp = new float[]1, 2;
PieChartView pieChart = new PieChartView(getContext(), calculateValues(deCalculat));
RelativeLayout.LayoutParams pieLayout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
pieLayout.setMargins(200, 10, 0, 0);
pieChart.setLayoutParams(pieLayout);
layout.addView(pieChart);
int x = 850;
int y = 860;
for (String country : pieInfo.listCountries)
RelativeLayout.LayoutParams tvLayout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
tvLayout.setMargins(70, x, 0, 0);
x += 80;
TextView legend = new TextView(getContext());
legend.setText(country);
legend.setLayoutParams(tvLayout);
layout.addView(legend);
int[] colorsChart = pieChart.colors;
int nrCuloare = pieInfo.listCountries.indexOf(country);
RelativeLayout.LayoutParams imgViewLayout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
imgViewLayout.height = 50;
imgViewLayout.width = 50;
imgViewLayout.setMargins(10, y, 0, 0);
ImageView imageView = new ImageView(getContext());
imageView.setBackgroundColor(colorsChart[nrCuloare]);
imageView.setLayoutParams(imgViewLayout);
layout.addView(imageView);
y += 80;
);
return root;
private float[] calculateValues(float[] values)
Log.d("onDraw_CalculateValues","being_CALLED");
float total = 0;
float[] degreeValues = new float[values.length];
for (int i = 0; i < values.length; i++)
total += values[i];
for (int i = 0; i < values.length; i++)
degreeValues[i] = 360 * (values[i] / total);
return degreeValues;
private void updateListView()
listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
@SuppressLint("StaticFieldLeak")
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
Object u = listView.getItemAtPosition(position);
User user = (User) u;
createDialog(user);
);
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener()
@SuppressLint("StaticFieldLeak")
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
Object deleteUser = listView.getItemAtPosition(position);
new AsyncTask<Void, Void, Void>()
@Override
protected Void doInBackground(Void... voids)
roomDbInstance.getUsersDao().eraseUser((User) deleteUser);
return null;
@Override
protected void onPostExecute(Void aVoid)
super.onPostExecute(aVoid);
userListAdapter.remove((User) deleteUser);
nrRecords = userListAdapter.getCount();
userListAdapter.notifyDataSetChanged();
.execute();
return false;
);
private void createDialog(User received)
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.update_user, null);
TextView ip_Update = view.findViewById(R.id.ip_updateUser);
TextView nickname = view.findViewById(R.id.nickname_updateUser);
ip_Update.setText(received.getIp());
nickname.setText(received.getNickname());
Button updateBtn = view.findViewById(R.id.btn_update);
builder.setView(view);
AlertDialog dialog1 = builder.show();
updateBtn.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if (!nickname.getText().toString().equals(received.getNickname()))
InputMethodManager inputMethodManager = (InputMethodManager)
getActivity().getApplicationContext().getSystemService(getContext().INPUT_METHOD_SERVICE);
// Hide the soft keyboard
inputMethodManager.hideSoftInputFromWindow(nickname.getWindowToken(), 0);
received.setNickname(nickname.getText().toString());
userListAdapter.notifyDataSetChanged();
updateOnDatabase(received.getId(), nickname.getText().toString());
dialog1.dismiss();
else
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setMessage("No changes?");
builder.setCancelable(true);
builder.setPositiveButton("Yup", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
);
builder.setNegativeButton("Nope", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
dialog1.dismiss();
);
builder.show();
@SuppressLint("StaticFieldLeak")
private void updateOnDatabase(int id, String new_nickname)
new AsyncTask<Void, Void, Void>()
@Override
protected Void doInBackground(Void... voids)
roomDbInstance.getUsersDao().updateUser(id, new_nickname);
return null;
.execute();
);
nickname.setOnEditorActionListener(new TextView.OnEditorActionListener()
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
if (actionId == EditorInfo.IME_ACTION_DONE)
InputMethodManager inputMethodManager = (InputMethodManager)
getActivity().getApplicationContext().getSystemService(getContext().INPUT_METHOD_SERVICE);
// Hide the soft keyboard
inputMethodManager.hideSoftInputFromWindow(nickname.getWindowToken(), 0);
// Toast.makeText(getContext(), nickname.getText(), Toast.LENGTH_SHORT).show();
return true;
return false;
);
public class PieInfo
ArrayList<String> listCountries = new ArrayList<>();
ArrayList<Float> pondereCountries = new ArrayList<>();
PieInfo()
public ArrayList<String> getListCountries()
return listCountries;
public void setListCountries(ArrayList<String> listCountries)
this.listCountries = listCountries;
public ArrayList<Float> getPondereCountries()
return pondereCountries;
public void setPondereCountries(ArrayList<Float> pondereCountries)
this.pondereCountries = pondereCountries;
private PieInfo calculPonderi()
PieInfo pieInfo = new PieInfo();
// ArrayList<String> listCountries = new ArrayList<>();
// ArrayList<Float> pondereCountries = new ArrayList<>();
for (int j = 0; j < users.size(); j++)
float counterCountry = 1;
String aux = users.get(j).getCountry();
pieInfo.listCountries.add(aux);
for (int i = 0; i < arrayList.size(); i++)
if (aux.equals(arrayList.get(i).getCountry()))
counterCountry++;
// Toast.makeText(getContext(),String.valueOf(counterCountry), Toast.LENGTH_SHORT).show();
pieInfo.pondereCountries.add(counterCountry);
return pieInfo;
@SuppressLint("StaticFieldLeak")
private void populateAdapter()
// Log.d("populateReached","Reached!");
new AsyncTask<Void, Void, Void>()
@Override
protected Void doInBackground(Void... voids)
users = roomDbInstance.getUsersDao().getAllUsers();
arrayList.addAll(users);
return null;
@Override
protected void onPostExecute(Void aVoid)
super.onPostExecute(aVoid);
listView.setAdapter(userListAdapter);
nrRecords = userListAdapter.getCount();
userListAdapter.notifyDataSetChanged();
.execute();
public ListUsersFragment()
//Required empty constructor
private void displayRating()
ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener()
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser)
Toast.makeText(getContext(), "" + rating, Toast.LENGTH_SHORT).show();
tv.setText("Thanks for the feedback!");
);
@Override
public void onAttach(Context context)
super.onAttach(context);
listener = (OnDataPassListener) getActivity();
public class PieChartView extends View
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int[] colors = Color.BLACK, Color.CYAN, Color.GREEN, Color.RED, Color.BLUE;
private RectF rectangle = new RectF(10, 10, 800, 800);
private float[] valueDegrees;
private float tmp = 0;
public PieChartView(Context context, float[] values)
super(context);
valueDegrees = new float[values.length];
for (int i = 0; i < valueDegrees.length; i++)
valueDegrees[i] = values[i];
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
for (int i = 0; i < valueDegrees.length; i++)
if (i == 0)
paint.setColor(colors[i]);
canvas.drawArc(rectangle, 0, valueDegrees[i], true, paint);
else
tmp += valueDegrees[i - 1];
paint.setColor(colors[i]);
canvas.drawArc(rectangle, tmp, valueDegrees[i], true, paint);
Log.d("onDraw","beingCalled");
【问题讨论】:
第二次它显示的颜色比它应该显示的颜色少,但空间划分保持正确,尝试不使用 AlertDialog,它就像一个魅力,但我需要在同一片段中的单独窗口中显示 PieChart .. 【参考方案1】:您必须了解,对于给定的View
,onDraw()
通常会被多次调用。它是 Android 屏幕刷新机制的一部分。在这种情况下,这可能是因为View
大小的微小变化(由于重新布局)。
因此,最好限制 onDraw()
函数更改对象的状态。您的PieChartView
违反了该原则; tmp
正在更改中。
要解决此问题,请将 tmp
设为局部变量,而不是成员变量。
【讨论】:
感谢您的见解和宝贵的时间。以上是关于activex 如何调用OnDraw函数的主要内容,如果未能解决你的问题,请参考以下文章